UNPKG

9.73 kBJavaScriptView Raw
1/** @license MIT License (c) copyright 2010-2014 original author or authors */
2
3/**
4 * Promises/A+ and when() implementation
5 * when is part of the cujoJS family of libraries (http://cujojs.com/)
6 * @author Brian Cavalier
7 * @author John Hann
8 * @version 3.4.2
9 */
10(function(define) { 'use strict';
11define(function (require) {
12
13 var timed = require('./lib/decorators/timed');
14 var array = require('./lib/decorators/array');
15 var flow = require('./lib/decorators/flow');
16 var fold = require('./lib/decorators/fold');
17 var inspect = require('./lib/decorators/inspect');
18 var generate = require('./lib/decorators/iterate');
19 var progress = require('./lib/decorators/progress');
20 var withThis = require('./lib/decorators/with');
21 var unhandledRejection = require('./lib/decorators/unhandledRejection');
22 var TimeoutError = require('./lib/TimeoutError');
23
24 var Promise = [array, flow, fold, generate, progress,
25 inspect, withThis, timed, unhandledRejection]
26 .reduce(function(Promise, feature) {
27 return feature(Promise);
28 }, require('./lib/Promise'));
29
30 var slice = Array.prototype.slice;
31
32 // Public API
33
34 when.promise = promise; // Create a pending promise
35 when.resolve = Promise.resolve; // Create a resolved promise
36 when.reject = Promise.reject; // Create a rejected promise
37
38 when.lift = lift; // lift a function to return promises
39 when['try'] = attempt; // call a function and return a promise
40 when.attempt = attempt; // alias for when.try
41
42 when.iterate = Promise.iterate; // Generate a stream of promises
43 when.unfold = Promise.unfold; // Generate a stream of promises
44
45 when.join = join; // Join 2 or more promises
46
47 when.all = all; // Resolve a list of promises
48 when.settle = settle; // Settle a list of promises
49
50 when.any = lift(Promise.any); // One-winner race
51 when.some = lift(Promise.some); // Multi-winner race
52 when.race = lift(Promise.race); // First-to-settle race
53
54 when.map = map; // Array.map() for promises
55 when.filter = filter; // Array.filter() for promises
56 when.reduce = reduce; // Array.reduce() for promises
57 when.reduceRight = reduceRight; // Array.reduceRight() for promises
58
59 when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable
60
61 when.Promise = Promise; // Promise constructor
62 when.defer = defer; // Create a {promise, resolve, reject} tuple
63
64 // Error types
65
66 when.TimeoutError = TimeoutError;
67
68 /**
69 * Get a trusted promise for x, or by transforming x with onFulfilled
70 *
71 * @param {*} x
72 * @param {function?} onFulfilled callback to be called when x is
73 * successfully fulfilled. If promiseOrValue is an immediate value, callback
74 * will be invoked immediately.
75 * @param {function?} onRejected callback to be called when x is
76 * rejected.
77 * @param {function?} onProgress callback to be called when progress updates
78 * are issued for x. @deprecated
79 * @returns {Promise} a new promise that will fulfill with the return
80 * value of callback or errback or the completion value of promiseOrValue if
81 * callback and/or errback is not supplied.
82 */
83 function when(x, onFulfilled, onRejected) {
84 var p = Promise.resolve(x);
85 if(arguments.length < 2) {
86 return p;
87 }
88
89 return arguments.length > 3
90 ? p.then(onFulfilled, onRejected, arguments[3])
91 : p.then(onFulfilled, onRejected);
92 }
93
94 /**
95 * Creates a new promise whose fate is determined by resolver.
96 * @param {function} resolver function(resolve, reject, notify)
97 * @returns {Promise} promise whose fate is determine by resolver
98 */
99 function promise(resolver) {
100 return new Promise(resolver);
101 }
102
103 /**
104 * Lift the supplied function, creating a version of f that returns
105 * promises, and accepts promises as arguments.
106 * @param {function} f
107 * @returns {Function} version of f that returns promises
108 */
109 function lift(f) {
110 return function() {
111 return _apply(f, this, slice.call(arguments));
112 };
113 }
114
115 /**
116 * Call f in a future turn, with the supplied args, and return a promise
117 * for the result.
118 * @param {function} f
119 * @returns {Promise}
120 */
121 function attempt(f /*, args... */) {
122 /*jshint validthis:true */
123 return _apply(f, this, slice.call(arguments, 1));
124 }
125
126 /**
127 * try/lift helper that allows specifying thisArg
128 * @private
129 */
130 function _apply(f, thisArg, args) {
131 return Promise.all(args).then(function(args) {
132 return f.apply(thisArg, args);
133 });
134 }
135
136 /**
137 * Creates a {promise, resolver} pair, either or both of which
138 * may be given out safely to consumers.
139 * @return {{promise: Promise, resolve: function, reject: function, notify: function}}
140 */
141 function defer() {
142 return new Deferred();
143 }
144
145 function Deferred() {
146 var p = Promise._defer();
147
148 function resolve(x) { p._handler.resolve(x); }
149 function reject(x) { p._handler.reject(x); }
150 function notify(x) { p._handler.notify(x); }
151
152 this.promise = p;
153 this.resolve = resolve;
154 this.reject = reject;
155 this.notify = notify;
156 this.resolver = { resolve: resolve, reject: reject, notify: notify };
157 }
158
159 /**
160 * Determines if x is promise-like, i.e. a thenable object
161 * NOTE: Will return true for *any thenable object*, and isn't truly
162 * safe, since it may attempt to access the `then` property of x (i.e.
163 * clever/malicious getters may do weird things)
164 * @param {*} x anything
165 * @returns {boolean} true if x is promise-like
166 */
167 function isPromiseLike(x) {
168 return x && typeof x.then === 'function';
169 }
170
171 /**
172 * Return a promise that will resolve only once all the supplied arguments
173 * have resolved. The resolution value of the returned promise will be an array
174 * containing the resolution values of each of the arguments.
175 * @param {...*} arguments may be a mix of promises and values
176 * @returns {Promise}
177 */
178 function join(/* ...promises */) {
179 return Promise.all(arguments);
180 }
181
182 /**
183 * Return a promise that will fulfill once all input promises have
184 * fulfilled, or reject when any one input promise rejects.
185 * @param {array|Promise} promises array (or promise for an array) of promises
186 * @returns {Promise}
187 */
188 function all(promises) {
189 return when(promises, Promise.all);
190 }
191
192 /**
193 * Return a promise that will always fulfill with an array containing
194 * the outcome states of all input promises. The returned promise
195 * will only reject if `promises` itself is a rejected promise.
196 * @param {array|Promise} promises array (or promise for an array) of promises
197 * @returns {Promise} promise for array of settled state descriptors
198 */
199 function settle(promises) {
200 return when(promises, Promise.settle);
201 }
202
203 /**
204 * Promise-aware array map function, similar to `Array.prototype.map()`,
205 * but input array may contain promises or values.
206 * @param {Array|Promise} promises array of anything, may contain promises and values
207 * @param {function(x:*, index:Number):*} mapFunc map function which may
208 * return a promise or value
209 * @returns {Promise} promise that will fulfill with an array of mapped values
210 * or reject if any input promise rejects.
211 */
212 function map(promises, mapFunc) {
213 return when(promises, function(promises) {
214 return Promise.map(promises, mapFunc);
215 });
216 }
217
218 /**
219 * Filter the provided array of promises using the provided predicate. Input may
220 * contain promises and values
221 * @param {Array|Promise} promises array of promises and values
222 * @param {function(x:*, index:Number):boolean} predicate filtering predicate.
223 * Must return truthy (or promise for truthy) for items to retain.
224 * @returns {Promise} promise that will fulfill with an array containing all items
225 * for which predicate returned truthy.
226 */
227 function filter(promises, predicate) {
228 return when(promises, function(promises) {
229 return Promise.filter(promises, predicate);
230 });
231 }
232
233 /**
234 * Traditional reduce function, similar to `Array.prototype.reduce()`, but
235 * input may contain promises and/or values, and reduceFunc
236 * may return either a value or a promise, *and* initialValue may
237 * be a promise for the starting value.
238 * @param {Array|Promise} promises array or promise for an array of anything,
239 * may contain a mix of promises and values.
240 * @param {function(accumulated:*, x:*, index:Number):*} f reduce function
241 * @returns {Promise} that will resolve to the final reduced value
242 */
243 function reduce(promises, f /*, initialValue */) {
244 /*jshint unused:false*/
245 var args = slice.call(arguments, 1);
246 return when(promises, function(array) {
247 args.unshift(array);
248 return Promise.reduce.apply(Promise, args);
249 });
250 }
251
252 /**
253 * Traditional reduce function, similar to `Array.prototype.reduceRight()`, but
254 * input may contain promises and/or values, and reduceFunc
255 * may return either a value or a promise, *and* initialValue may
256 * be a promise for the starting value.
257 * @param {Array|Promise} promises array or promise for an array of anything,
258 * may contain a mix of promises and values.
259 * @param {function(accumulated:*, x:*, index:Number):*} f reduce function
260 * @returns {Promise} that will resolve to the final reduced value
261 */
262 function reduceRight(promises, f /*, initialValue */) {
263 /*jshint unused:false*/
264 var args = slice.call(arguments, 1);
265 return when(promises, function(array) {
266 args.unshift(array);
267 return Promise.reduceRight.apply(Promise, args);
268 });
269 }
270
271 return when;
272});
273})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });