/* Ext.promise.Consequence adapted from: [DeftJS](https://github.com/deftjs/deftjs5) Copyright (c) 2012-2013 [DeftJS Framework Contributors](http://deftjs.org) Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License). */ /** * Consequences are used internally by a Deferred to capture and notify callbacks, and * propagate their transformed results as fulfillment or rejection. * * Developers never directly interact with a Consequence. * * A Consequence forms a chain between two Deferreds, where the result of the first * Deferred is transformed by the corresponding callback before being applied to the * second Deferred. * * Each time a Deferred's `then` method is called, it creates a new Consequence that will * be triggered once its originating Deferred has been fulfilled or rejected. A Consequence * captures a pair of optional onFulfilled and onRejected callbacks. * * Each Consequence has its own Deferred (which in turn has a Promise) that is resolved or * rejected when the Consequence is triggered. When a Consequence is triggered by its * originating Deferred, it calls the corresponding callback and propagates the transformed * result to its own Deferred; resolved with the callback return value or rejected with any * error thrown by the callback. * * @since 6.0.0 * @private */Ext.define('Ext.promise.Consequence', function(Consequence) { return { /** * @property {Ext.promise.Promise} * Promise of the future value of this Consequence. */ promise: null, /** * @property {Ext.promise.Deferred} deferred Internal Deferred for this Consequence. * * @private */ deferred: null, /** * @property {Function} onFulfilled Callback to execute when this Consequence is triggered * with a fulfillment value. * * @private */ onFulfilled: null, /** * @property {Function} onRejected Callback to execute when this Consequence is triggered * with a rejection reason. * * @private */ onRejected: null, /** * @property {Function} onProgress Callback to execute when this Consequence is updated * with a progress value. * * @private */ onProgress: null, /** * @param {Function} onFulfilled Callback to execute to transform a fulfillment value. * @param {Function} onRejected Callback to execute to transform a rejection reason. */ constructor: function(onFulfilled, onRejected, onProgress) { var me = this; me.onFulfilled = onFulfilled; me.onRejected = onRejected; me.onProgress = onProgress; me.deferred = new Ext.promise.Deferred(); me.promise = me.deferred.promise; }, /** * Trigger this Consequence with the specified action and value. * * @param {String} action Completion action (i.e. fulfill or reject). * @param {Mixed} value Fulfillment value or rejection reason. */ trigger: function(action, value) { var me = this, deferred = me.deferred; switch (action) { case 'fulfill': me.propagate(value, me.onFulfilled, deferred, deferred.resolve); break; case 'reject': me.propagate(value, me.onRejected, deferred, deferred.reject); break; } }, /** * Update this Consequence with the specified progress value. * * @param {Mixed} value Progress value. */ update: function(progress) { if (Ext.isFunction(this.onProgress)) { progress = this.onProgress(progress); } this.deferred.update(progress); }, /** * Transform and propagate the specified value using the * optional callback and propagate the transformed result. * * @param {Mixed} value Value to transform and/or propagate. * @param {Function} [callback] Callback to use to transform the value. * @param {Function} deferred Deferred to use to propagate the value, if no callback * was specified. * @param {Function} deferredMethod Deferred method to call to propagate the value, * if no callback was specified. * * @private */ propagate: function(value, callback, deferred, deferredMethod) { if (Ext.isFunction(callback)) { this.schedule(function() { try { deferred.resolve(callback(value)); } catch (e) { deferred.reject(e); } }); } else { deferredMethod.call(this.deferred, value); } }, /** * Schedules the specified callback function to be executed on the next turn of the * event loop. * * @param {Function} callback Callback function. * * @private */ schedule: function(callback) { var n = Consequence.queueSize++; Consequence.queue[n] = callback; if (!n) { // if (queue was empty) Ext.asap(Consequence.dispatch); } }, statics: { /** * @property {Function[]} queue The queue of callbacks pending. This array is never * shrunk to reduce GC thrash but instead its elements will be set to `null`. * * @private */ queue: new Array(10000), /** * @property {Number} queueSize The number of callbacks in the `queue`. * * @private */ queueSize: 0, /** * This method drains the callback queue and calls each callback in order. * * @private */ dispatch: function() { var queue = Consequence.queue, fn, i; // The queue could grow on each call, so we cannot cache queueSize here. for (i = 0; i < Consequence.queueSize; ++i) { fn = queue[i]; queue[i] = null; // release our reference on the callback fn(); } Consequence.queueSize = 0; } }}});