UNPKG

8.14 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 */
9(function(define) { 'use strict';
10define(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); });