UNPKG

promisesds

Version:

ES6 Promises data structures and utils

143 lines (132 loc) 4.75 kB
module.exports = function() { "use strict"; /** * The orderedPromises object keeps an ordered list of promises for a single * resource. It provides a next callback that is whenever a more updated * result is available. This guarantees the order of the results preventing * old results getting mixed with newer ones. * The ordering is only kept on the client side so this is ideal for stateless * requests. * @param {array} promises An initial list of promises to track, be careful * to initializw the callbacks with options if the promises * may have already been completed * @param {Object} options { * next: @see orderedPromises.next(); * last: @see orderedPromises.next(); * discarded: @see orderedPromises.next(); * } */ var OrderedPromises = function(promises, options){ var self = this; options = options || {}; promises = promises || []; this._promises = []; this.next(options.next, options.nextFail); this.last(options.last, options.lastFail); this.discarded(options.discarded); promises.forEach(function(promise){ self.push(promise); }); }; /** * Private function to go over the promises array when a new one is completed * and discard old promises and call the next callback and the last callback * if it's the last one * @param {OrderedPromises} self instance of the object * @param {[]} promises array of promises * @param {Promise} promise Promise that has completed * @param {arguments} argsObj args of the solved promise * @param {boolean} success if the promise completed successfully */ function process(self, promises, promise, value, success){ while (promises.length){ var current = promises.shift(); if(promise !== current.promise){ current.discarded = true; self._discarded(current.promise); } else { self[success ? '_next' : '_nextFail'](promise, value); if (!promises.length){ self[success ? '_last' : '_lastFail'](promise, value); } return; } } } var noop = function(){}; OrderedPromises.prototype = { /** * Add a new promise to the list. * @param {Promise} promise to add * @return {OrderedPromises} chainable return */ push: function(promise){ var self = this; var obj = { promise: promise, discarded: false }; this._promises.push(obj); promise.then(function(value){ if (!obj.discarded){ process(self, self._promises, obj.promise, value, true); } }, function(value){ if (!obj.discarded){ process(self, self._promises, obj.promise, value, false); } }); return this; }, /** * Callback triggered when the last promise in the list is completed * @param {Function} handler handler for a successfully completed promise * @see next for the callback specification * @param {Function} failure handler for a rejected promise * @see last for the callback specification * @return {OrderedPromises} chainable return */ last: function(handler, failure){ this._last = handler || noop; this._lastFail = failure || noop; return this; }, /** * Callback triggered when a more updated result is available, that is, no promise * after this has been completed. Just before this callback is executed the previous * not yet completed promises are discarded. * @param {Function} handler handler for a successfully completed promise * handler(promise, promise_resolved_args...) * @param {Function} failure handler for a rejected promise * handler(promise, promise_rejected_args...) * @return {OrderedPromises} chainable return */ next: function(handler, failure){ this._next = handler || noop; this._nextFail = failure || noop; return this; }, /** * It creates a copy of the promises array currently on the object, it contains * all promises introduced that have not been discarded or completed * @return {[]} array of promises */ promises: function(){ return this._promises.map(function(obj){ return obj.promise; }); }, /** * Callback for the discarded promises so it's possible to keep track of the * promises that didn't complete before a more updated result was available. * It may be useful to release resources or abort them. * @param {Function} handler handler(promise) * @return {OrderedPromises} chainable return */ discarded: function(handler){ this._discarded = handler || noop; return this; } }; return OrderedPromises; }();