define("dojo/Deferred", [ "./has", "./_base/lang", "./errors/CancelError", "./promise/Promise", "./promise/instrumentation" ], function(has, lang, CancelError, Promise, instrumentation){ "use strict"; // module: // dojo/Deferred var PROGRESS = 0, RESOLVED = 1, REJECTED = 2; var FULFILLED_ERROR_MESSAGE = "This deferred has already been fulfilled."; var freezeObject = Object.freeze || function(){}; var signalWaiting = function(waiting, type, result, rejection, deferred){ if( 1 ){ if(type === REJECTED && Deferred.instrumentRejected && waiting.length === 0){ Deferred.instrumentRejected(result, false, rejection, deferred); } } for(var i = 0; i < waiting.length; i++){ signalListener(waiting[i], type, result, rejection); } }; var signalListener = function(listener, type, result, rejection){ var func = listener[type]; var deferred = listener.deferred; if(func){ try{ var newResult = func(result); if(type === PROGRESS){ if(typeof newResult !== "undefined"){ signalDeferred(deferred, type, newResult); } }else{ if(newResult && typeof newResult.then === "function"){ listener.cancel = newResult.cancel; newResult.then( // Only make resolvers if they're actually going to be used makeDeferredSignaler(deferred, RESOLVED), makeDeferredSignaler(deferred, REJECTED), makeDeferredSignaler(deferred, PROGRESS)); return; } signalDeferred(deferred, RESOLVED, newResult); } }catch(error){ signalDeferred(deferred, REJECTED, error); } }else{ signalDeferred(deferred, type, result); } if( 1 ){ if(type === REJECTED && Deferred.instrumentRejected){ Deferred.instrumentRejected(result, !!func, rejection, deferred.promise); } } }; var makeDeferredSignaler = function(deferred, type){ return function(value){ signalDeferred(deferred, type, value); }; }; var signalDeferred = function(deferred, type, result){ if(!deferred.isCanceled()){ switch(type){ case PROGRESS: deferred.progress(result); break; case RESOLVED: deferred.resolve(result); break; case REJECTED: deferred.reject(result); break; } } }; var Deferred = function(canceler){ // summary: // Creates a new deferred. This API is preferred over // `dojo/_base/Deferred`. // description: // Creates a new deferred, as an abstraction over (primarily) // asynchronous operations. The deferred is the private interface // that should not be returned to calling code. That's what the // `promise` is for. See `dojo/promise/Promise`. // canceler: Function? // Will be invoked if the deferred is canceled. The canceler // receives the reason the deferred was canceled as its argument. // The deferred is rejected with its return value, or a new // `dojo/errors/CancelError` instance. // promise: dojo/promise/Promise // The public promise object that clients can add callbacks to. var promise = this.promise = new Promise(); var deferred = this; var fulfilled, result, rejection; var canceled = false; var waiting = []; if( 1 && Error.captureStackTrace){ Error.captureStackTrace(deferred, Deferred); Error.captureStackTrace(promise, Deferred); } this.isResolved = promise.isResolved = function(){ // summary: // Checks whether the deferred has been resolved. // returns: Boolean return fulfilled === RESOLVED; }; this.isRejected = promise.isRejected = function(){ // summary: // Checks whether the deferred has been rejected. // returns: Boolean return fulfilled === REJECTED; }; this.isFulfilled = promise.isFulfilled = function(){ // summary: // Checks whether the deferred has been resolved or rejected. // returns: Boolean return !!fulfilled; }; this.isCanceled = promise.isCanceled = function(){ // summary: // Checks whether the deferred has been canceled. // returns: Boolean return canceled; }; this.progress = function(update, strict){ // summary: // Emit a progress update on the deferred. // description: // Emit a progress update on the deferred. Progress updates // can be used to communicate updates about the asynchronous // operation before it has finished. // update: any // The progress update. Passed to progbacks. // strict: Boolean? // If strict, will throw an error if the deferred has already // been fulfilled and consequently no progress can be emitted. // returns: dojo/promise/Promise // Returns the original promise for the deferred. if(!fulfilled){ signalWaiting(waiting, PROGRESS, update, null, deferred); return promise; }else if(strict === true){ throw new Error(FULFILLED_ERROR_MESSAGE); }else{ return promise; } }; this.resolve = function(value, strict){ // summary: // Resolve the deferred. // description: // Resolve the deferred, putting it in a success state. // value: any // The result of the deferred. Passed to callbacks. // strict: Boolean? // If strict, will throw an error if the deferred has already // been fulfilled and consequently cannot be resolved. // returns: dojo/promise/Promise // Returns the original promise for the deferred. if(!fulfilled){ // Set fulfilled, store value. After signaling waiting listeners unset // waiting. signalWaiting(waiting, fulfilled = RESOLVED, result = value, null, deferred); waiting = null; return promise; }else if(strict === true){ throw new Error(FULFILLED_ERROR_MESSAGE); }else{ return promise; } }; var reject = this.reject = function(error, strict){ // summary: // Reject the deferred. // description: // Reject the deferred, putting it in an error state. // error: any // The error result of the deferred. Passed to errbacks. // strict: Boolean? // If strict, will throw an error if the deferred has already // been fulfilled and consequently cannot be rejected. // returns: dojo/promise/Promise // Returns the original promise for the deferred. if(!fulfilled){ if( 1 && Error.captureStackTrace){ Error.captureStackTrace(rejection = {}, reject); } signalWaiting(waiting, fulfilled = REJECTED, result = error, rejection, deferred); waiting = null; return promise; }else if(strict === true){ throw new Error(FULFILLED_ERROR_MESSAGE); }else{ return promise; } }; this.then = promise.then = function(callback, errback, progback){ // summary: // Add new callbacks to the deferred. // description: // Add new callbacks to the deferred. Callbacks can be added // before or after the deferred is fulfilled. // callback: Function? // Callback to be invoked when the promise is resolved. // Receives the resolution value. // errback: Function? // Callback to be invoked when the promise is rejected. // Receives the rejection error. // progback: Function? // Callback to be invoked when the promise emits a progress // update. Receives the progress update. // returns: dojo/promise/Promise // Returns a new promise for the result of the callback(s). // This can be used for chaining many asynchronous operations. var listener = [progback, callback, errback]; // Ensure we cancel the promise we're waiting for, or if callback/errback // have returned a promise, cancel that one. listener.cancel = promise.cancel; listener.deferred = new Deferred(function(reason){ // Check whether cancel is really available, returned promises are not // required to expose `cancel` return listener.cancel && listener.cancel(reason); }); if(fulfilled && !waiting){ signalListener(listener, fulfilled, result, rejection); }else{ waiting.push(listener); } return listener.deferred.promise; }; this.cancel = promise.cancel = function(reason, strict){ // summary: // Inform the deferred it may cancel its asynchronous operation. // description: // Inform the deferred it may cancel its asynchronous operation. // The deferred's (optional) canceler is invoked and the // deferred will be left in a rejected state. Can affect other // promises that originate with the same deferred. // reason: any // A message that may be sent to the deferred's canceler, // explaining why it's being canceled. // strict: Boolean? // If strict, will throw an error if the deferred has already // been fulfilled and consequently cannot be canceled. // returns: any // Returns the rejection reason if the deferred was canceled // normally. if(!fulfilled){ // Cancel can be called even after the deferred is fulfilled if(canceler){ var returnedReason = canceler(reason); reason = typeof returnedReason === "undefined" ? reason : returnedReason; } canceled = true; if(!fulfilled){ // Allow canceler to provide its own reason, but fall back to a CancelError if(typeof reason === "undefined"){ reason = new CancelError(); } reject(reason); return reason; }else if(fulfilled === REJECTED && result === reason){ return reason; } }else if(strict === true){ throw new Error(FULFILLED_ERROR_MESSAGE); } }; freezeObject(promise); }; Deferred.prototype.toString = function(){ // returns: String // Returns `[object Deferred]`. return "[object Deferred]"; }; if(instrumentation){ instrumentation(Deferred); } return Deferred; });