when.js 8.0 KB

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