PageRenderTime 23ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/ajax/libs/when/0.9.3/when.js

https://gitlab.com/Mirros/cdnjs
JavaScript | 371 lines | 188 code | 66 blank | 117 comment | 17 complexity | 0fc6fc45e26edabdc11f28a38a759258 MD5 | raw file
  1. /**
  2. * @license Copyright (c) 2011 Brian Cavalier
  3. * LICENSE: see the LICENSE.txt file. If file is missing, this file is subject
  4. * to the MIT License at: http://www.opensource.org/licenses/mit-license.php.
  5. */
  6. //
  7. // when.js 0.9.3
  8. //
  9. (function(define, undef) {
  10. define([], function() {
  11. // No-op function used in function replacement in various
  12. // places below.
  13. function noop() {}
  14. // Use freeze if it exists
  15. var freeze = Object.freeze || noop;
  16. // Creates a new, CommonJS compliant, Deferred with fully isolated
  17. // resolver and promise parts, either or both of which may be given out
  18. // safely to consumers.
  19. // The Deferred itself has the full API: resolve, reject, progress, and
  20. // then. The resolver has resolve, reject, and progress. The promise
  21. // only has then.
  22. function defer() {
  23. var deferred, promise, resolver, result, listeners, tail,
  24. _then, _progress, complete;
  25. _then = function(callback, errback, progback) {
  26. var d, listener;
  27. listener = {
  28. deferred: (d = defer()),
  29. resolve: callback,
  30. reject: errback,
  31. progress: progback
  32. };
  33. if(listeners) {
  34. // Append new listener if linked list already initialized
  35. tail = tail.next = listener;
  36. } else {
  37. // Init linked list
  38. listeners = tail = listener;
  39. }
  40. return d.promise;
  41. };
  42. function then(callback, errback, progback) {
  43. return _then(callback, errback, progback);
  44. }
  45. function resolve(val) {
  46. complete('resolve', val);
  47. }
  48. function reject(err) {
  49. complete('reject', err);
  50. }
  51. _progress = function(update) {
  52. var listener, progress;
  53. listener = listeners;
  54. while(listener) {
  55. progress = listener.progress;
  56. if(progress) progress(update);
  57. listener = listener.next;
  58. }
  59. };
  60. function progress(update) {
  61. _progress(update);
  62. }
  63. complete = function(which, val) {
  64. // Save original _then
  65. var origThen = _then;
  66. // Replace _then with one that immediately notifies
  67. // with the result.
  68. _then = function newThen(callback, errback) {
  69. var promise = origThen(callback, errback);
  70. notify(which);
  71. return promise;
  72. };
  73. // Replace complete so that this Deferred
  74. // can only be completed once. Note that this leaves
  75. // notify() intact so that it can be used in the
  76. // rewritten _then above.
  77. // Replace _progress, so that subsequent attempts
  78. // to issue progress throw.
  79. complete = _progress = function alreadyCompleted() {
  80. throw new Error("already completed");
  81. };
  82. // Final result of this Deferred. This is immutable
  83. result = val;
  84. // Notify listeners
  85. notify(which);
  86. };
  87. function notify(which) {
  88. // Traverse all listeners registered directly with this Deferred,
  89. // also making sure to handle chained thens
  90. while(listeners) {
  91. var listener, ldeferred, newResult, handler;
  92. listener = listeners;
  93. ldeferred = listener.deferred;
  94. listeners = listeners.next;
  95. handler = listener[which];
  96. if(handler) {
  97. try {
  98. newResult = handler(result);
  99. if(isPromise(newResult)) {
  100. // If the handler returned a promise, chained deferreds
  101. // should complete only after that promise does.
  102. _chain(newResult, ldeferred);
  103. } else {
  104. // Complete deferred from chained then()
  105. // FIXME: Which is correct?
  106. // The first always mutates the chained value, even if it is undefined
  107. // The second will only mutate if newResult !== undefined
  108. // ldeferred[which](newResult);
  109. ldeferred[which](newResult === undef ? result : newResult);
  110. }
  111. } catch(e) {
  112. // Exceptions cause chained deferreds to complete
  113. // TODO: Should it *also* switch this promise's handlers to failed??
  114. // I think no.
  115. // which = 'reject';
  116. ldeferred.reject(e);
  117. }
  118. }
  119. }
  120. }
  121. // The full Deferred object, with both Promise and Resolver parts
  122. deferred = {};
  123. // Promise and Resolver parts
  124. // Expose Promise API
  125. promise = deferred.promise = {
  126. then: (deferred.then = then)
  127. };
  128. // Expose Resolver API
  129. resolver = deferred.resolver = {
  130. resolve: (deferred.resolve = resolve),
  131. reject: (deferred.reject = reject),
  132. progress: (deferred.progress = progress)
  133. };
  134. // Freeze Promise and Resolver APIs
  135. freeze(promise);
  136. freeze(resolver);
  137. return deferred;
  138. }
  139. // Determines if promiseOrValue is a promise or not. Uses the feature
  140. // test from http://wiki.commonjs.org/wiki/Promises/A to determine if
  141. // promiseOrValue is a promise.
  142. //
  143. // Parameters:
  144. // promiseOrValue - anything
  145. //
  146. // Return true if promiseOrValue is a promise.
  147. function isPromise(promiseOrValue) {
  148. return promiseOrValue && typeof promiseOrValue.then === 'function';
  149. }
  150. // Register a handler for a promise or immediate value
  151. //
  152. // Parameters:
  153. // promiseOrValue - anything
  154. //
  155. // Returns a new promise that will resolve:
  156. // 1. if promiseOrValue is a promise, when promiseOrValue resolves
  157. // 2. if promiseOrValue is a value, immediately
  158. function when(promiseOrValue, callback, errback, progressHandler) {
  159. var deferred, resolve, reject;
  160. deferred = defer();
  161. resolve = callback ? callback : function(val) { return val; };
  162. reject = errback ? errback : function(err) { return err; };
  163. if(isPromise(promiseOrValue)) {
  164. // If it's a promise, ensure that deferred will complete when promiseOrValue
  165. // completes.
  166. promiseOrValue.then(resolve, reject,
  167. function(update) { progressHandler(update); }
  168. );
  169. _chain(promiseOrValue, deferred);
  170. } else {
  171. // If it's a value, resolve immediately
  172. deferred.resolve(resolve(promiseOrValue));
  173. }
  174. return deferred.promise;
  175. }
  176. // Return a promise that will resolve when howMany of the supplied promisesOrValues
  177. // have resolved. The resolution value of the returned promise will be an array of
  178. // length howMany containing the resolutions values of the triggering promisesOrValues.
  179. function some(promisesOrValues, howMany, callback, errback, progressHandler) {
  180. var toResolve, results, ret, deferred, resolver, rejecter, handleProgress;
  181. toResolve = Math.max(0, Math.min(howMany, promisesOrValues.length));
  182. results = [];
  183. deferred = defer();
  184. ret = (callback || errback || progressHandler)
  185. ? deferred.then(callback, errback, progressHandler)
  186. : deferred.promise;
  187. // Resolver for promises. Captures the value and resolves
  188. // the returned promise when toResolve reaches zero.
  189. // Overwrites resolver var with a noop once promise has
  190. // be resolved to cover case where n < promises.length
  191. resolver = function(val) {
  192. results.push(val);
  193. if(--toResolve === 0) {
  194. resolver = handleProgress = noop;
  195. deferred.resolve(results);
  196. }
  197. };
  198. // Wrapper so that resolver can be replaced
  199. function resolve(val) {
  200. resolver(val);
  201. }
  202. // Rejecter for promises. Rejects returned promise
  203. // immediately, and overwrites rejecter var with a noop
  204. // once promise to cover case where n < promises.length.
  205. // TODO: Consider rejecting only when N (or promises.length - N?)
  206. // promises have been rejected instead of only one?
  207. rejecter = function(err) {
  208. rejecter = handleProgress = noop;
  209. deferred.reject(err);
  210. };
  211. // Wrapper so that rejecer can be replaced
  212. function reject(err) {
  213. rejecter(err);
  214. }
  215. handleProgress = function(update) {
  216. deferred.progress(update);
  217. };
  218. function progress(update) {
  219. handleProgress(update);
  220. }
  221. if(toResolve === 0) {
  222. deferred.resolve(results);
  223. } else {
  224. var promiseOrValue, i = 0;
  225. while((promiseOrValue = promisesOrValues[i++])) {
  226. when(promiseOrValue, resolve, reject, progress);
  227. }
  228. }
  229. return ret;
  230. }
  231. // Return a promise that will resolve only once all the supplied promisesOrValues
  232. // have resolved. The resolution value of the returned promise will be an array
  233. // containing the resolution values of each of the promisesOrValues.
  234. function all(promisesOrValues, callback, errback, progressHandler) {
  235. return some(promisesOrValues, promisesOrValues.length, callback, errback, progressHandler);
  236. }
  237. // Return a promise that will resolve when any one of the supplied promisesOrValues
  238. // has resolved. The resolution value of the returned promise will be the resolution
  239. // value of the triggering promiseOrValue.
  240. function any(promisesOrValues, callback, errback, progressHandler) {
  241. return some(promisesOrValues, 1, callback, errback, progressHandler);
  242. }
  243. // Ensure that resolution of promiseOrValue will complete resolver with the completion
  244. // value of promiseOrValue, or instead with optionalValue if it is provided.
  245. //
  246. // Parameters:
  247. // promiseOrValue - Promise, that when completed, will trigger completion of resolver,
  248. // or value that will trigger immediate resolution of resolver
  249. // resolver - Resolver to complete when promise completes
  250. // resolveValue - optional value to use as the resolution value
  251. // used to resolve second, rather than the resolution
  252. // value of first.
  253. //
  254. // Returns a new promise that will complete when promiseOrValue is completed,
  255. // with the completion value of promiseOrValue, or instead with optionalValue if it
  256. // is provided.
  257. function chain(promiseOrValue, resolver, resolveValue) {
  258. var inputPromise, initChain;
  259. inputPromise = when(promiseOrValue);
  260. // Check against args length instead of resolvedValue === undefined, since
  261. // undefined may be a valid resolution value.
  262. initChain = arguments.length > 2
  263. ? function(resolver) { return _chain(inputPromise, resolver, resolveValue) }
  264. : function(resolver) { return _chain(inputPromise, resolver); };
  265. // Setup chain to supplied resolver
  266. initChain(resolver);
  267. // Setup chain to new promise
  268. return initChain(when.defer()).promise;
  269. }
  270. // Internal chain helper that does not create a new deferred/promise
  271. // Always returns it's 2nd arg.
  272. // NOTE: deferred must be a when.js deferred, or a resolver whose functions
  273. // can be called without their original context.
  274. function _chain(promise, deferred, resolveValue) {
  275. promise.then(
  276. // If resolveValue was supplied, need to wrap up a new function
  277. // If not, can use deferred.resolve directly
  278. arguments.length > 2
  279. ? function() { deferred.resolve(resolveValue) }
  280. : deferred.resolve,
  281. deferred.reject,
  282. deferred.progress
  283. );
  284. return deferred;
  285. }
  286. //
  287. // Public API
  288. //
  289. when.defer = defer;
  290. when.isPromise = isPromise;
  291. when.some = some;
  292. when.all = all;
  293. when.any = any;
  294. when.chain = chain;
  295. return when;
  296. }); // define
  297. })(typeof define != 'undefined'
  298. // use define for AMD if available
  299. ? define
  300. // If no define, look for module to export as a CommonJS module.
  301. // If no define or module, attach to current context.
  302. : typeof module != 'undefined'
  303. ? function(deps, factory) { module.exports = factory(); }
  304. : function(deps, factory) { this.when = factory(); }
  305. );