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 | */
|
9 | (function(define) { 'use strict';
|
10 | define(function (require) {
|
11 |
|
12 | var timed = require('./lib/decorators/timed');
|
13 | var array = require('./lib/decorators/array');
|
14 | var flow = require('./lib/decorators/flow');
|
15 | var fold = require('./lib/decorators/fold');
|
16 | var inspect = require('./lib/decorators/inspect');
|
17 | var generate = require('./lib/decorators/iterate');
|
18 | var progress = require('./lib/decorators/progress');
|
19 | var withThis = require('./lib/decorators/with');
|
20 | var unhandledRejection = require('./lib/decorators/unhandledRejection');
|
21 | var TimeoutError = require('./lib/TimeoutError');
|
22 |
|
23 | var Promise = [array, flow, fold, generate, progress,
|
24 | inspect, withThis, timed, unhandledRejection]
|
25 | .reduce(function(Promise, feature) {
|
26 | return feature(Promise);
|
27 | }, require('./lib/Promise'));
|
28 |
|
29 | var apply = require('./lib/apply')(Promise);
|
30 |
|
31 | // Public API
|
32 |
|
33 | when.promise = promise; // Create a pending promise
|
34 | when.resolve = Promise.resolve; // Create a resolved promise
|
35 | when.reject = Promise.reject; // Create a rejected promise
|
36 |
|
37 | when.lift = lift; // lift a function to return promises
|
38 | when['try'] = attempt; // call a function and return a promise
|
39 | when.attempt = attempt; // alias for when.try
|
40 |
|
41 | when.iterate = Promise.iterate; // DEPRECATED (use cujojs/most streams) Generate a stream of promises
|
42 | when.unfold = Promise.unfold; // DEPRECATED (use cujojs/most streams) Generate a stream of promises
|
43 |
|
44 | when.join = join; // Join 2 or more promises
|
45 |
|
46 | when.all = all; // Resolve a list of promises
|
47 | when.settle = settle; // Settle a list of promises
|
48 |
|
49 | when.any = lift(Promise.any); // One-winner race
|
50 | when.some = lift(Promise.some); // Multi-winner race
|
51 | when.race = lift(Promise.race); // First-to-settle race
|
52 |
|
53 | when.map = map; // Array.map() for promises
|
54 | when.filter = filter; // Array.filter() for promises
|
55 | when.reduce = lift(Promise.reduce); // Array.reduce() for promises
|
56 | when.reduceRight = lift(Promise.reduceRight); // Array.reduceRight() for promises
|
57 |
|
58 | when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable
|
59 |
|
60 | when.Promise = Promise; // Promise constructor
|
61 | when.defer = defer; // Create a {promise, resolve, reject} tuple
|
62 |
|
63 | // Error types
|
64 |
|
65 | when.TimeoutError = TimeoutError;
|
66 |
|
67 | /**
|
68 | * Get a trusted promise for x, or by transforming x with onFulfilled
|
69 | *
|
70 | * @param {*} x
|
71 | * @param {function?} onFulfilled callback to be called when x is
|
72 | * successfully fulfilled. If promiseOrValue is an immediate value, callback
|
73 | * will be invoked immediately.
|
74 | * @param {function?} onRejected callback to be called when x is
|
75 | * rejected.
|
76 | * @param {function?} onProgress callback to be called when progress updates
|
77 | * are issued for x. @deprecated
|
78 | * @returns {Promise} a new promise that will fulfill with the return
|
79 | * value of callback or errback or the completion value of promiseOrValue if
|
80 | * callback and/or errback is not supplied.
|
81 | */
|
82 | function when(x, onFulfilled, onRejected, onProgress) {
|
83 | var p = Promise.resolve(x);
|
84 | if (arguments.length < 2) {
|
85 | return p;
|
86 | }
|
87 |
|
88 | return p.then(onFulfilled, onRejected, onProgress);
|
89 | }
|
90 |
|
91 | /**
|
92 | * Creates a new promise whose fate is determined by resolver.
|
93 | * @param {function} resolver function(resolve, reject, notify)
|
94 | * @returns {Promise} promise whose fate is determine by resolver
|
95 | */
|
96 | function promise(resolver) {
|
97 | return new Promise(resolver);
|
98 | }
|
99 |
|
100 | /**
|
101 | * Lift the supplied function, creating a version of f that returns
|
102 | * promises, and accepts promises as arguments.
|
103 | * @param {function} f
|
104 | * @returns {Function} version of f that returns promises
|
105 | */
|
106 | function lift(f) {
|
107 | return function() {
|
108 | for(var i=0, l=arguments.length, a=new Array(l); i<l; ++i) {
|
109 | a[i] = arguments[i];
|
110 | }
|
111 | return apply(f, this, a);
|
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 | for(var i=0, l=arguments.length-1, a=new Array(l); i<l; ++i) {
|
124 | a[i] = arguments[i+1];
|
125 | }
|
126 | return apply(f, this, a);
|
127 | }
|
128 |
|
129 | /**
|
130 | * Creates a {promise, resolver} pair, either or both of which
|
131 | * may be given out safely to consumers.
|
132 | * @return {{promise: Promise, resolve: function, reject: function, notify: function}}
|
133 | */
|
134 | function defer() {
|
135 | return new Deferred();
|
136 | }
|
137 |
|
138 | function Deferred() {
|
139 | var p = Promise._defer();
|
140 |
|
141 | function resolve(x) { p._handler.resolve(x); }
|
142 | function reject(x) { p._handler.reject(x); }
|
143 | function notify(x) { p._handler.notify(x); }
|
144 |
|
145 | this.promise = p;
|
146 | this.resolve = resolve;
|
147 | this.reject = reject;
|
148 | this.notify = notify;
|
149 | this.resolver = { resolve: resolve, reject: reject, notify: notify };
|
150 | }
|
151 |
|
152 | /**
|
153 | * Determines if x is promise-like, i.e. a thenable object
|
154 | * NOTE: Will return true for *any thenable object*, and isn't truly
|
155 | * safe, since it may attempt to access the `then` property of x (i.e.
|
156 | * clever/malicious getters may do weird things)
|
157 | * @param {*} x anything
|
158 | * @returns {boolean} true if x is promise-like
|
159 | */
|
160 | function isPromiseLike(x) {
|
161 | return x && typeof x.then === 'function';
|
162 | }
|
163 |
|
164 | /**
|
165 | * Return a promise that will resolve only once all the supplied arguments
|
166 | * have resolved. The resolution value of the returned promise will be an array
|
167 | * containing the resolution values of each of the arguments.
|
168 | * @param {...*} arguments may be a mix of promises and values
|
169 | * @returns {Promise}
|
170 | */
|
171 | function join(/* ...promises */) {
|
172 | return Promise.all(arguments);
|
173 | }
|
174 |
|
175 | /**
|
176 | * Return a promise that will fulfill once all input promises have
|
177 | * fulfilled, or reject when any one input promise rejects.
|
178 | * @param {array|Promise} promises array (or promise for an array) of promises
|
179 | * @returns {Promise}
|
180 | */
|
181 | function all(promises) {
|
182 | return when(promises, Promise.all);
|
183 | }
|
184 |
|
185 | /**
|
186 | * Return a promise that will always fulfill with an array containing
|
187 | * the outcome states of all input promises. The returned promise
|
188 | * will only reject if `promises` itself is a rejected promise.
|
189 | * @param {array|Promise} promises array (or promise for an array) of promises
|
190 | * @returns {Promise} promise for array of settled state descriptors
|
191 | */
|
192 | function settle(promises) {
|
193 | return when(promises, Promise.settle);
|
194 | }
|
195 |
|
196 | /**
|
197 | * Promise-aware array map function, similar to `Array.prototype.map()`,
|
198 | * but input array may contain promises or values.
|
199 | * @param {Array|Promise} promises array of anything, may contain promises and values
|
200 | * @param {function(x:*, index:Number):*} mapFunc map function which may
|
201 | * return a promise or value
|
202 | * @returns {Promise} promise that will fulfill with an array of mapped values
|
203 | * or reject if any input promise rejects.
|
204 | */
|
205 | function map(promises, mapFunc) {
|
206 | return when(promises, function(promises) {
|
207 | return Promise.map(promises, mapFunc);
|
208 | });
|
209 | }
|
210 |
|
211 | /**
|
212 | * Filter the provided array of promises using the provided predicate. Input may
|
213 | * contain promises and values
|
214 | * @param {Array|Promise} promises array of promises and values
|
215 | * @param {function(x:*, index:Number):boolean} predicate filtering predicate.
|
216 | * Must return truthy (or promise for truthy) for items to retain.
|
217 | * @returns {Promise} promise that will fulfill with an array containing all items
|
218 | * for which predicate returned truthy.
|
219 | */
|
220 | function filter(promises, predicate) {
|
221 | return when(promises, function(promises) {
|
222 | return Promise.filter(promises, predicate);
|
223 | });
|
224 | }
|
225 |
|
226 | return when;
|
227 | });
|
228 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
|