summaryrefslogtreecommitdiff
path: root/lib/dojo/_base/Deferred.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dojo/_base/Deferred.js')
-rw-r--r--lib/dojo/_base/Deferred.js106
1 files changed, 55 insertions, 51 deletions
diff --git a/lib/dojo/_base/Deferred.js b/lib/dojo/_base/Deferred.js
index 3193024ab..c5992c966 100644
--- a/lib/dojo/_base/Deferred.js
+++ b/lib/dojo/_base/Deferred.js
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
@@ -10,42 +10,43 @@ dojo._hasResource["dojo._base.Deferred"] = true;
dojo.provide("dojo._base.Deferred");
dojo.require("dojo._base.lang");
+
(function(){
- var mutator = function(){};
+ var mutator = function(){};
var freeze = Object.freeze || function(){};
// A deferred provides an API for creating and resolving a promise.
dojo.Deferred = function(/*Function?*/canceller){
// summary:
// Deferreds provide a generic means for encapsulating an asynchronous
- // operation and notifying users of the completion and result of the operation.
+ // operation and notifying users of the completion and result of the operation.
// description:
// The dojo.Deferred API is based on the concept of promises that provide a
// generic interface into the eventual completion of an asynchronous action.
- // The motivation for promises fundamentally is about creating a
- // separation of concerns that allows one to achieve the same type of
- // call patterns and logical data flow in asynchronous code as can be
- // achieved in synchronous code. Promises allows one
- // to be able to call a function purely with arguments needed for
- // execution, without conflating the call with concerns of whether it is
- // sync or async. One shouldn't need to alter a call's arguments if the
- // implementation switches from sync to async (or vice versa). By having
- // async functions return promises, the concerns of making the call are
- // separated from the concerns of asynchronous interaction (which are
+ // The motivation for promises fundamentally is about creating a
+ // separation of concerns that allows one to achieve the same type of
+ // call patterns and logical data flow in asynchronous code as can be
+ // achieved in synchronous code. Promises allows one
+ // to be able to call a function purely with arguments needed for
+ // execution, without conflating the call with concerns of whether it is
+ // sync or async. One shouldn't need to alter a call's arguments if the
+ // implementation switches from sync to async (or vice versa). By having
+ // async functions return promises, the concerns of making the call are
+ // separated from the concerns of asynchronous interaction (which are
// handled by the promise).
- //
- // The dojo.Deferred is a type of promise that provides methods for fulfilling the
- // promise with a successful result or an error. The most important method for
- // working with Dojo's promises is the then() method, which follows the
+ //
+ // The dojo.Deferred is a type of promise that provides methods for fulfilling the
+ // promise with a successful result or an error. The most important method for
+ // working with Dojo's promises is the then() method, which follows the
// CommonJS proposed promise API. An example of using a Dojo promise:
- //
+ //
// | var resultingPromise = someAsyncOperation.then(function(result){
// | ... handle result ...
// | },
// | function(error){
// | ... handle error ...
// | });
- //
- // The .then() call returns a new promise that represents the result of the
+ //
+ // The .then() call returns a new promise that represents the result of the
// execution of the callback. The callbacks will never affect the original promises value.
//
// The dojo.Deferred instances also provide the following functions for backwards compatibility:
@@ -55,7 +56,7 @@ dojo.require("dojo._base.lang");
// * callback(result)
// * errback(result)
//
- // Callbacks are allowed to return promisesthemselves, so
+ // Callbacks are allowed to return promises themselves, so
// you can build complicated sequences of events with ease.
//
// The creator of the Deferred may specify a canceller. The canceller
@@ -115,7 +116,7 @@ dojo.require("dojo._base.lang");
// | renderDataitem(data[x]);
// | }
// | d.callback(true);
- // | }catch(e){
+ // | }catch(e){
// | d.errback(new Error("rendering failed"));
// | }
// | return d;
@@ -129,7 +130,7 @@ dojo.require("dojo._base.lang");
// | // again, so we could chain adding callbacks or save the
// | // deferred for later should we need to be notified again.
// example:
- // In this example, renderLotsOfData is syncrhonous and so both
+ // In this example, renderLotsOfData is synchronous and so both
// versions are pretty artificial. Putting the data display on a
// timeout helps show why Deferreds rock:
//
@@ -142,7 +143,7 @@ dojo.require("dojo._base.lang");
// | renderDataitem(data[x]);
// | }
// | d.callback(true);
- // | }catch(e){
+ // | }catch(e){
// | d.errback(new Error("rendering failed"));
// | }
// | }, 100);
@@ -157,11 +158,11 @@ dojo.require("dojo._base.lang");
// Note that the caller doesn't have to change his code at all to
// handle the asynchronous case.
var result, finished, isError, head, nextListener;
- var promise = this.promise = {};
+ var promise = (this.promise = {});
function complete(value){
if(finished){
- throw new Error("This deferred has already been resolved");
+ throw new Error("This deferred has already been resolved");
}
result = value;
finished = true;
@@ -172,7 +173,7 @@ dojo.require("dojo._base.lang");
while(!mutated && nextListener){
var listener = nextListener;
nextListener = nextListener.next;
- if(mutated = (listener.progress == mutator)){ // assignment and check
+ if((mutated = (listener.progress == mutator))){ // assignment and check
finished = false;
}
var func = (isError ? listener.error : listener.resolved);
@@ -184,6 +185,9 @@ dojo.require("dojo._base.lang");
continue;
}
var unchanged = mutated && newResult === undefined;
+ if(mutated && !unchanged){
+ isError = newResult instanceof Error;
+ }
listener.deferred[unchanged && isError ? "reject" : "resolve"](unchanged ? result : newResult);
}
catch (e) {
@@ -196,7 +200,7 @@ dojo.require("dojo._base.lang");
listener.deferred.resolve(result);
}
}
- }
+ }
}
// calling resolve will resolve the promise
this.resolve = this.callback = function(value){
@@ -211,7 +215,7 @@ dojo.require("dojo._base.lang");
// calling error will indicate that the promise failed
this.reject = this.errback = function(error){
// summary:
- // Fulfills the Deferred instance as an error with the provided error
+ // Fulfills the Deferred instance as an error with the provided error
isError = true;
this.fired = 1;
complete(error);
@@ -228,7 +232,7 @@ dojo.require("dojo._base.lang");
while(listener){
var progress = listener.progress;
progress && progress(update);
- listener = listener.next;
+ listener = listener.next;
}
};
this.addCallbacks = function(/*Function?*/callback, /*Function?*/errback){
@@ -237,35 +241,35 @@ dojo.require("dojo._base.lang");
};
// provide the implementation of the promise
this.then = promise.then = function(/*Function?*/resolvedCallback, /*Function?*/errorCallback, /*Function?*/progressCallback){
- // summary
- // Adds a fulfilledHandler, errorHandler, and progressHandler to be called for
- // completion of a promise. The fulfilledHandler is called when the promise
- // is fulfilled. The errorHandler is called when a promise fails. The
- // progressHandler is called for progress events. All arguments are optional
- // and non-function values are ignored. The progressHandler is not only an
- // optional argument, but progress events are purely optional. Promise
+ // summary:
+ // Adds a fulfilledHandler, errorHandler, and progressHandler to be called for
+ // completion of a promise. The fulfilledHandler is called when the promise
+ // is fulfilled. The errorHandler is called when a promise fails. The
+ // progressHandler is called for progress events. All arguments are optional
+ // and non-function values are ignored. The progressHandler is not only an
+ // optional argument, but progress events are purely optional. Promise
// providers are not required to ever create progress events.
- //
- // This function will return a new promise that is fulfilled when the given
- // fulfilledHandler or errorHandler callback is finished. This allows promise
- // operations to be chained together. The value returned from the callback
- // handler is the fulfillment value for the returned promise. If the callback
+ //
+ // This function will return a new promise that is fulfilled when the given
+ // fulfilledHandler or errorHandler callback is finished. This allows promise
+ // operations to be chained together. The value returned from the callback
+ // handler is the fulfillment value for the returned promise. If the callback
// throws an error, the returned promise will be moved to failed state.
- //
+ //
// example:
// An example of using a CommonJS compliant promise:
// | asyncComputeTheAnswerToEverything().
// | then(addTwo).
// | then(printResult, onError);
- // | >44
- //
+ // | >44
+ //
var returnDeferred = progressCallback == mutator ? this : new dojo.Deferred(promise.cancel);
var listener = {
- resolved: resolvedCallback,
- error: errorCallback,
- progress: progressCallback,
+ resolved: resolvedCallback,
+ error: errorCallback,
+ progress: progressCallback,
deferred: returnDeferred
- };
+ };
if(nextListener){
head = head.next = listener;
}
@@ -291,7 +295,7 @@ dojo.require("dojo._base.lang");
deferred.reject(error);
}
}
- }
+ };
freeze(promise);
};
dojo.extend(dojo.Deferred, {
@@ -312,7 +316,7 @@ dojo.require("dojo._base.lang");
})();
dojo.when = function(promiseOrValue, /*Function?*/callback, /*Function?*/errback, /*Function?*/progressHandler){
// summary:
- // This provides normalization between normal synchronous values and
+ // This provides normalization between normal synchronous values and
// asynchronous promises, so you can interact with them in a common way
// example:
// | function printFirstAndList(items){