123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- // Copyright 2005 Bob Ippolito. All Rights Reserved.
- // Modifications Copyright 2009 The Closure Library Authors.
- // All Rights Reserved.
- /**
- * Portions of this code are from MochiKit, received by The Closure
- * Library Authors under the MIT license. All other code is Copyright
- * 2005-2009 The Closure Library Authors. All Rights Reserved.
- */
- /**
- * @fileoverview Class for tracking multiple asynchronous operations and
- * handling the results. The DeferredList object here is patterned after the
- * DeferredList object in the Twisted python networking framework.
- *
- * Based on the MochiKit code.
- *
- * See: http://twistedmatrix.com/projects/core/documentation/howto/defer.html
- *
- * @author brenneman@google.com (Shawn Brenneman)
- */
- goog.provide('goog.async.DeferredList');
- goog.require('goog.async.Deferred');
- /**
- * Constructs an object that waits on the results of multiple asynchronous
- * operations and marshals the results. It is itself a <code>Deferred</code>,
- * and may have an execution sequence of callback functions added to it. Each
- * <code>DeferredList</code> instance is single use and may be fired only once.
- *
- * The default behavior of a <code>DeferredList</code> is to wait for a success
- * or error result from every <code>Deferred</code> in its input list. Once
- * every result is available, the <code>DeferredList</code>'s execution sequence
- * is fired with a list of <code>[success, result]</code> array pairs, where
- * <code>success</code> is a boolean indicating whether <code>result</code> was
- * the product of a callback or errback. The list's completion criteria and
- * result list may be modified by setting one or more of the boolean options
- * documented below.
- *
- * <code>Deferred</code> instances passed into a <code>DeferredList</code> are
- * independent, and may have additional callbacks and errbacks added to their
- * execution sequences after they are passed as inputs to the list.
- *
- * @param {!Array<!goog.async.Deferred>} list An array of deferred results to
- * wait for.
- * @param {boolean=} opt_fireOnOneCallback Whether to stop waiting as soon as
- * one input completes successfully. In this case, the
- * <code>DeferredList</code>'s callback chain will be called with a two
- * element array, <code>[index, result]</code>, where <code>index</code>
- * identifies which input <code>Deferred</code> produced the successful
- * <code>result</code>.
- * @param {boolean=} opt_fireOnOneErrback Whether to stop waiting as soon as one
- * input reports an error. The failing result is passed to the
- * <code>DeferredList</code>'s errback sequence.
- * @param {boolean=} opt_consumeErrors When true, any errors fired by a
- * <code>Deferred</code> in the input list will be captured and replaced
- * with a succeeding null result. Any callbacks added to the
- * <code>Deferred</code> after its use in the <code>DeferredList</code> will
- * receive null instead of the error.
- * @param {Function=} opt_canceler A function that will be called if the
- * <code>DeferredList</code> is canceled. @see goog.async.Deferred#cancel
- * @param {Object=} opt_defaultScope The default scope to invoke callbacks or
- * errbacks in.
- * @constructor
- * @extends {goog.async.Deferred}
- */
- goog.async.DeferredList = function(
- list, opt_fireOnOneCallback, opt_fireOnOneErrback, opt_consumeErrors,
- opt_canceler, opt_defaultScope) {
- goog.async.DeferredList.base(this, 'constructor',
- opt_canceler, opt_defaultScope);
- /**
- * The list of Deferred objects to wait for.
- * @const {!Array<!goog.async.Deferred>}
- * @private
- */
- this.list_ = list;
- /**
- * The stored return values of the Deferred objects.
- * @const {!Array}
- * @private
- */
- this.deferredResults_ = [];
- /**
- * Whether to fire on the first successful callback instead of waiting for
- * every Deferred to complete.
- * @const {boolean}
- * @private
- */
- this.fireOnOneCallback_ = !!opt_fireOnOneCallback;
- /**
- * Whether to fire on the first error result received instead of waiting for
- * every Deferred to complete.
- * @const {boolean}
- * @private
- */
- this.fireOnOneErrback_ = !!opt_fireOnOneErrback;
- /**
- * Whether to stop error propagation on the input Deferred objects. If the
- * DeferredList sees an error from one of the Deferred inputs, the error will
- * be captured, and the Deferred will be returned to success state with a null
- * return value.
- * @const {boolean}
- * @private
- */
- this.consumeErrors_ = !!opt_consumeErrors;
- /**
- * The number of input deferred objects that have fired.
- * @private {number}
- */
- this.numFinished_ = 0;
- for (var i = 0; i < list.length; i++) {
- var d = list[i];
- d.addCallbacks(goog.bind(this.handleCallback_, this, i, true),
- goog.bind(this.handleCallback_, this, i, false));
- }
- if (list.length == 0 && !this.fireOnOneCallback_) {
- this.callback(this.deferredResults_);
- }
- };
- goog.inherits(goog.async.DeferredList, goog.async.Deferred);
- /**
- * Registers the result from an input deferred callback or errback. The result
- * is returned and may be passed to additional handlers in the callback chain.
- *
- * @param {number} index The index of the firing deferred object in the input
- * list.
- * @param {boolean} success Whether the result is from a callback or errback.
- * @param {*} result The result of the callback or errback.
- * @return {*} The result, to be handled by the next handler in the deferred's
- * callback chain (if any). If consumeErrors is set, an error result is
- * replaced with null.
- * @private
- */
- goog.async.DeferredList.prototype.handleCallback_ = function(
- index, success, result) {
- this.numFinished_++;
- this.deferredResults_[index] = [success, result];
- if (!this.hasFired()) {
- if (this.fireOnOneCallback_ && success) {
- this.callback([index, result]);
- } else if (this.fireOnOneErrback_ && !success) {
- this.errback(result);
- } else if (this.numFinished_ == this.list_.length) {
- this.callback(this.deferredResults_);
- }
- }
- if (this.consumeErrors_ && !success) {
- result = null;
- }
- return result;
- };
- /** @override */
- goog.async.DeferredList.prototype.errback = function(res) {
- goog.async.DeferredList.base(this, 'errback', res);
- // On error, cancel any pending requests.
- for (var i = 0; i < this.list_.length; i++) {
- this.list_[i].cancel();
- }
- };
- /**
- * Creates a <code>DeferredList</code> that gathers results from multiple
- * <code>Deferred</code> inputs. If all inputs succeed, the callback is fired
- * with the list of results as a flat array. If any input fails, the list's
- * errback is fired immediately with the offending error, and all other pending
- * inputs are canceled.
- *
- * @param {!Array<!goog.async.Deferred>} list The list of <code>Deferred</code>
- * inputs to wait for.
- * @return {!goog.async.Deferred} The deferred list of results from the inputs
- * if they all succeed, or the error result of the first input to fail.
- */
- goog.async.DeferredList.gatherResults = function(list) {
- return new goog.async.DeferredList(list, false, true).
- addCallback(function(results) {
- var output = [];
- for (var i = 0; i < results.length; i++) {
- output[i] = results[i][1];
- }
- return output;
- });
- };
|