2 * @overview es6-promise - a tiny implementation of Promises/A+.
3 * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
4 * @license Licensed under MIT license
5 * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
9 (function (global, factory) {
10 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11 typeof define === 'function' && define.amd ? define(factory) :
12 (global.ES6Promise = factory());
13 }(this, (function () { 'use strict';
15 function objectOrFunction(x) {
16 return typeof x === 'function' || typeof x === 'object' && x !== null;
19 function isFunction(x) {
20 return typeof x === 'function';
23 var _isArray = undefined;
25 _isArray = function (x) {
26 return Object.prototype.toString.call(x) === '[object Array]';
29 _isArray = Array.isArray;
32 var isArray = _isArray;
35 var vertxNext = undefined;
36 var customSchedulerFn = undefined;
38 var asap = function asap(callback, arg) {
39 queue[len] = callback;
43 // If len is 2, that means that we need to schedule an async flush.
44 // If additional callbacks are queued before the queue is flushed, they
45 // will be processed by this flush that we are scheduling.
46 if (customSchedulerFn) {
47 customSchedulerFn(flush);
54 function setScheduler(scheduleFn) {
55 customSchedulerFn = scheduleFn;
58 function setAsap(asapFn) {
62 var browserWindow = typeof window !== 'undefined' ? window : undefined;
63 var browserGlobal = browserWindow || {};
64 var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
65 var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]';
67 // test for web worker but not in IE10
68 var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
71 function useNextTick() {
72 // node version 0.10.x displays a deprecation warning when nextTick is used recursively
73 // see https://github.com/cujojs/when/issues/410 for details
75 return process.nextTick(flush);
80 function useVertxTimer() {
81 if (typeof vertxNext !== 'undefined') {
87 return useSetTimeout();
90 function useMutationObserver() {
92 var observer = new BrowserMutationObserver(flush);
93 var node = document.createTextNode('');
94 observer.observe(node, { characterData: true });
97 node.data = iterations = ++iterations % 2;
102 function useMessageChannel() {
103 var channel = new MessageChannel();
104 channel.port1.onmessage = flush;
106 return channel.port2.postMessage(0);
110 function useSetTimeout() {
111 // Store setTimeout reference so es6-promise will be unaffected by
112 // other code modifying setTimeout (like sinon.useFakeTimers())
113 var globalSetTimeout = setTimeout;
115 return globalSetTimeout(flush, 1);
119 var queue = new Array(1000);
121 for (var i = 0; i < len; i += 2) {
122 var callback = queue[i];
123 var arg = queue[i + 1];
127 queue[i] = undefined;
128 queue[i + 1] = undefined;
134 function attemptVertx() {
137 var vertx = r('vertx');
138 vertxNext = vertx.runOnLoop || vertx.runOnContext;
139 return useVertxTimer();
141 return useSetTimeout();
145 var scheduleFlush = undefined;
146 // Decide what async method to use to triggering processing of queued callbacks:
148 scheduleFlush = useNextTick();
149 } else if (BrowserMutationObserver) {
150 scheduleFlush = useMutationObserver();
151 } else if (isWorker) {
152 scheduleFlush = useMessageChannel();
153 } else if (browserWindow === undefined && typeof require === 'function') {
154 scheduleFlush = attemptVertx();
156 scheduleFlush = useSetTimeout();
159 function then(onFulfillment, onRejection) {
160 var _arguments = arguments;
164 var child = new this.constructor(noop);
166 if (child[PROMISE_ID] === undefined) {
170 var _state = parent._state;
174 var callback = _arguments[_state - 1];
176 return invokeCallback(_state, child, callback, parent._result);
180 subscribe(parent, child, onFulfillment, onRejection);
187 `Promise.resolve` returns a promise that will become resolved with the
188 passed `value`. It is shorthand for the following:
191 let promise = new Promise(function(resolve, reject){
195 promise.then(function(value){
200 Instead of writing the above, your code now simply becomes the following:
203 let promise = Promise.resolve(1);
205 promise.then(function(value){
212 @param {Any} value value that the returned promise will be resolved with
214 @return {Promise} a promise that will become fulfilled with the given
217 function resolve(object) {
218 /*jshint validthis:true */
219 var Constructor = this;
221 if (object && typeof object === 'object' && object.constructor === Constructor) {
225 var promise = new Constructor(noop);
226 _resolve(promise, object);
230 var PROMISE_ID = Math.random().toString(36).substring(16);
234 var PENDING = void 0;
238 var GET_THEN_ERROR = new ErrorObject();
240 function selfFulfillment() {
241 return new TypeError("You cannot resolve a promise with itself");
244 function cannotReturnOwn() {
245 return new TypeError('A promises callback cannot return that same promise.');
248 function getThen(promise) {
252 GET_THEN_ERROR.error = error;
253 return GET_THEN_ERROR;
257 function tryThen(then, value, fulfillmentHandler, rejectionHandler) {
259 then.call(value, fulfillmentHandler, rejectionHandler);
265 function handleForeignThenable(promise, thenable, then) {
266 asap(function (promise) {
268 var error = tryThen(then, thenable, function (value) {
273 if (thenable !== value) {
274 _resolve(promise, value);
276 fulfill(promise, value);
278 }, function (reason) {
284 _reject(promise, reason);
285 }, 'Settle: ' + (promise._label || ' unknown promise'));
287 if (!sealed && error) {
289 _reject(promise, error);
294 function handleOwnThenable(promise, thenable) {
295 if (thenable._state === FULFILLED) {
296 fulfill(promise, thenable._result);
297 } else if (thenable._state === REJECTED) {
298 _reject(promise, thenable._result);
300 subscribe(thenable, undefined, function (value) {
301 return _resolve(promise, value);
302 }, function (reason) {
303 return _reject(promise, reason);
308 function handleMaybeThenable(promise, maybeThenable, then$$) {
309 if (maybeThenable.constructor === promise.constructor && then$$ === then && maybeThenable.constructor.resolve === resolve) {
310 handleOwnThenable(promise, maybeThenable);
312 if (then$$ === GET_THEN_ERROR) {
313 _reject(promise, GET_THEN_ERROR.error);
314 } else if (then$$ === undefined) {
315 fulfill(promise, maybeThenable);
316 } else if (isFunction(then$$)) {
317 handleForeignThenable(promise, maybeThenable, then$$);
319 fulfill(promise, maybeThenable);
324 function _resolve(promise, value) {
325 if (promise === value) {
326 _reject(promise, selfFulfillment());
327 } else if (objectOrFunction(value)) {
328 handleMaybeThenable(promise, value, getThen(value));
330 fulfill(promise, value);
334 function publishRejection(promise) {
335 if (promise._onerror) {
336 promise._onerror(promise._result);
342 function fulfill(promise, value) {
343 if (promise._state !== PENDING) {
347 promise._result = value;
348 promise._state = FULFILLED;
350 if (promise._subscribers.length !== 0) {
351 asap(publish, promise);
355 function _reject(promise, reason) {
356 if (promise._state !== PENDING) {
359 promise._state = REJECTED;
360 promise._result = reason;
362 asap(publishRejection, promise);
365 function subscribe(parent, child, onFulfillment, onRejection) {
366 var _subscribers = parent._subscribers;
367 var length = _subscribers.length;
369 parent._onerror = null;
371 _subscribers[length] = child;
372 _subscribers[length + FULFILLED] = onFulfillment;
373 _subscribers[length + REJECTED] = onRejection;
375 if (length === 0 && parent._state) {
376 asap(publish, parent);
380 function publish(promise) {
381 var subscribers = promise._subscribers;
382 var settled = promise._state;
384 if (subscribers.length === 0) {
388 var child = undefined,
389 callback = undefined,
390 detail = promise._result;
392 for (var i = 0; i < subscribers.length; i += 3) {
393 child = subscribers[i];
394 callback = subscribers[i + settled];
397 invokeCallback(settled, child, callback, detail);
403 promise._subscribers.length = 0;
406 function ErrorObject() {
410 var TRY_CATCH_ERROR = new ErrorObject();
412 function tryCatch(callback, detail) {
414 return callback(detail);
416 TRY_CATCH_ERROR.error = e;
417 return TRY_CATCH_ERROR;
421 function invokeCallback(settled, promise, callback, detail) {
422 var hasCallback = isFunction(callback),
425 succeeded = undefined,
429 value = tryCatch(callback, detail);
431 if (value === TRY_CATCH_ERROR) {
439 if (promise === value) {
440 _reject(promise, cannotReturnOwn());
448 if (promise._state !== PENDING) {
450 } else if (hasCallback && succeeded) {
451 _resolve(promise, value);
453 _reject(promise, error);
454 } else if (settled === FULFILLED) {
455 fulfill(promise, value);
456 } else if (settled === REJECTED) {
457 _reject(promise, value);
461 function initializePromise(promise, resolver) {
463 resolver(function resolvePromise(value) {
464 _resolve(promise, value);
465 }, function rejectPromise(reason) {
466 _reject(promise, reason);
478 function makePromise(promise) {
479 promise[PROMISE_ID] = id++;
480 promise._state = undefined;
481 promise._result = undefined;
482 promise._subscribers = [];
485 function Enumerator(Constructor, input) {
486 this._instanceConstructor = Constructor;
487 this.promise = new Constructor(noop);
489 if (!this.promise[PROMISE_ID]) {
490 makePromise(this.promise);
493 if (isArray(input)) {
495 this.length = input.length;
496 this._remaining = input.length;
498 this._result = new Array(this.length);
500 if (this.length === 0) {
501 fulfill(this.promise, this._result);
503 this.length = this.length || 0;
505 if (this._remaining === 0) {
506 fulfill(this.promise, this._result);
510 _reject(this.promise, validationError());
514 function validationError() {
515 return new Error('Array Methods must be provided an Array');
518 Enumerator.prototype._enumerate = function () {
519 var length = this.length;
520 var _input = this._input;
522 for (var i = 0; this._state === PENDING && i < length; i++) {
523 this._eachEntry(_input[i], i);
527 Enumerator.prototype._eachEntry = function (entry, i) {
528 var c = this._instanceConstructor;
529 var resolve$$ = c.resolve;
531 if (resolve$$ === resolve) {
532 var _then = getThen(entry);
534 if (_then === then && entry._state !== PENDING) {
535 this._settledAt(entry._state, i, entry._result);
536 } else if (typeof _then !== 'function') {
538 this._result[i] = entry;
539 } else if (c === Promise) {
540 var promise = new c(noop);
541 handleMaybeThenable(promise, entry, _then);
542 this._willSettleAt(promise, i);
544 this._willSettleAt(new c(function (resolve$$) {
545 return resolve$$(entry);
549 this._willSettleAt(resolve$$(entry), i);
553 Enumerator.prototype._settledAt = function (state, i, value) {
554 var promise = this.promise;
556 if (promise._state === PENDING) {
559 if (state === REJECTED) {
560 _reject(promise, value);
562 this._result[i] = value;
566 if (this._remaining === 0) {
567 fulfill(promise, this._result);
571 Enumerator.prototype._willSettleAt = function (promise, i) {
572 var enumerator = this;
574 subscribe(promise, undefined, function (value) {
575 return enumerator._settledAt(FULFILLED, i, value);
576 }, function (reason) {
577 return enumerator._settledAt(REJECTED, i, reason);
582 `Promise.all` accepts an array of promises, and returns a new promise which
583 is fulfilled with an array of fulfillment values for the passed promises, or
584 rejected with the reason of the first passed promise to be rejected. It casts all
585 elements of the passed iterable to promises as it runs this algorithm.
590 let promise1 = resolve(1);
591 let promise2 = resolve(2);
592 let promise3 = resolve(3);
593 let promises = [ promise1, promise2, promise3 ];
595 Promise.all(promises).then(function(array){
596 // The array here would be [ 1, 2, 3 ];
600 If any of the `promises` given to `all` are rejected, the first promise
601 that is rejected will be given as an argument to the returned promises's
602 rejection handler. For example:
607 let promise1 = resolve(1);
608 let promise2 = reject(new Error("2"));
609 let promise3 = reject(new Error("3"));
610 let promises = [ promise1, promise2, promise3 ];
612 Promise.all(promises).then(function(array){
613 // Code here never runs because there are rejected promises!
615 // error.message === "2"
621 @param {Array} entries array of promises
622 @param {String} label optional string for labeling the promise.
624 @return {Promise} promise that is fulfilled when all `promises` have been
625 fulfilled, or rejected if any of them become rejected.
628 function all(entries) {
629 return new Enumerator(this, entries).promise;
633 `Promise.race` returns a new promise which is settled in the same way as the
634 first passed promise to settle.
639 let promise1 = new Promise(function(resolve, reject){
640 setTimeout(function(){
641 resolve('promise 1');
645 let promise2 = new Promise(function(resolve, reject){
646 setTimeout(function(){
647 resolve('promise 2');
651 Promise.race([promise1, promise2]).then(function(result){
652 // result === 'promise 2' because it was resolved before promise1
657 `Promise.race` is deterministic in that only the state of the first
658 settled promise matters. For example, even if other promises given to the
659 `promises` array argument are resolved, but the first settled promise has
660 become rejected before the other promises became fulfilled, the returned
661 promise will become rejected:
664 let promise1 = new Promise(function(resolve, reject){
665 setTimeout(function(){
666 resolve('promise 1');
670 let promise2 = new Promise(function(resolve, reject){
671 setTimeout(function(){
672 reject(new Error('promise 2'));
676 Promise.race([promise1, promise2]).then(function(result){
677 // Code here never runs
679 // reason.message === 'promise 2' because promise 2 became rejected before
680 // promise 1 became fulfilled
684 An example real-world use case is implementing timeouts:
687 Promise.race([ajax('foo.json'), timeout(5000)])
692 @param {Array} promises array of promises to observe
694 @return {Promise} a promise which settles in the same way as the first passed
697 function race(entries) {
698 /*jshint validthis:true */
699 var Constructor = this;
701 if (!isArray(entries)) {
702 return new Constructor(function (_, reject) {
703 return reject(new TypeError('You must pass an array to race.'));
706 return new Constructor(function (resolve, reject) {
707 var length = entries.length;
708 for (var i = 0; i < length; i++) {
709 Constructor.resolve(entries[i]).then(resolve, reject);
716 `Promise.reject` returns a promise rejected with the passed `reason`.
717 It is shorthand for the following:
720 let promise = new Promise(function(resolve, reject){
721 reject(new Error('WHOOPS'));
724 promise.then(function(value){
725 // Code here doesn't run because the promise is rejected!
727 // reason.message === 'WHOOPS'
731 Instead of writing the above, your code now simply becomes the following:
734 let promise = Promise.reject(new Error('WHOOPS'));
736 promise.then(function(value){
737 // Code here doesn't run because the promise is rejected!
739 // reason.message === 'WHOOPS'
745 @param {Any} reason value that the returned promise will be rejected with.
747 @return {Promise} a promise rejected with the given `reason`.
749 function reject(reason) {
750 /*jshint validthis:true */
751 var Constructor = this;
752 var promise = new Constructor(noop);
753 _reject(promise, reason);
757 function needsResolver() {
758 throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
761 function needsNew() {
762 throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
766 Promise objects represent the eventual result of an asynchronous operation. The
767 primary way of interacting with a promise is through its `then` method, which
768 registers callbacks to receive either a promise's eventual value or the reason
769 why the promise cannot be fulfilled.
774 - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
775 - `thenable` is an object or function that defines a `then` method.
776 - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
777 - `exception` is a value that is thrown using the throw statement.
778 - `reason` is a value that indicates why a promise was rejected.
779 - `settled` the final resting state of a promise, fulfilled or rejected.
781 A promise can be in one of three states: pending, fulfilled, or rejected.
783 Promises that are fulfilled have a fulfillment value and are in the fulfilled
784 state. Promises that are rejected have a rejection reason and are in the
785 rejected state. A fulfillment value is never a thenable.
787 Promises can also be said to *resolve* a value. If this value is also a
788 promise, then the original promise's settled state will match the value's
789 settled state. So a promise that *resolves* a promise that rejects will
790 itself reject, and a promise that *resolves* a promise that fulfills will
798 let promise = new Promise(function(resolve, reject) {
806 promise.then(function(value) {
808 }, function(reason) {
816 Promises shine when abstracting away asynchronous interactions such as
820 function getJSON(url) {
821 return new Promise(function(resolve, reject){
822 let xhr = new XMLHttpRequest();
824 xhr.open('GET', url);
825 xhr.onreadystatechange = handler;
826 xhr.responseType = 'json';
827 xhr.setRequestHeader('Accept', 'application/json');
831 if (this.readyState === this.DONE) {
832 if (this.status === 200) {
833 resolve(this.response);
835 reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
842 getJSON('/posts.json').then(function(json) {
844 }, function(reason) {
849 Unlike callbacks, promises are great composable primitives.
855 ]).then(function(values){
856 values[0] // => postsJSON
857 values[1] // => commentsJSON
864 @param {function} resolver
868 function Promise(resolver) {
869 this[PROMISE_ID] = nextId();
870 this._result = this._state = undefined;
871 this._subscribers = [];
873 if (noop !== resolver) {
874 typeof resolver !== 'function' && needsResolver();
875 this instanceof Promise ? initializePromise(this, resolver) : needsNew();
881 Promise.resolve = resolve;
882 Promise.reject = reject;
883 Promise._setScheduler = setScheduler;
884 Promise._setAsap = setAsap;
885 Promise._asap = asap;
887 Promise.prototype = {
888 constructor: Promise,
891 The primary way of interacting with a promise is through its `then` method,
892 which registers callbacks to receive either a promise's eventual value or the
893 reason why the promise cannot be fulfilled.
896 findUser().then(function(user){
899 // user is unavailable, and you are given the reason why
906 The return value of `then` is itself a promise. This second, 'downstream'
907 promise is resolved with the return value of the first promise's fulfillment
908 or rejection handler, or rejected if the handler throws an exception.
911 findUser().then(function (user) {
913 }, function (reason) {
914 return 'default name';
915 }).then(function (userName) {
916 // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
917 // will be `'default name'`
920 findUser().then(function (user) {
921 throw new Error('Found user, but still unhappy');
922 }, function (reason) {
923 throw new Error('`findUser` rejected and we're unhappy');
924 }).then(function (value) {
926 }, function (reason) {
927 // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
928 // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
931 If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
934 findUser().then(function (user) {
935 throw new PedagogicalException('Upstream error');
936 }).then(function (value) {
938 }).then(function (value) {
940 }, function (reason) {
941 // The `PedgagocialException` is propagated all the way down to here
948 Sometimes the value you want to propagate to a downstream promise can only be
949 retrieved asynchronously. This can be achieved by returning a promise in the
950 fulfillment or rejection handler. The downstream promise will then be pending
951 until the returned promise is settled. This is called *assimilation*.
954 findUser().then(function (user) {
955 return findCommentsByAuthor(user);
956 }).then(function (comments) {
957 // The user's comments are now available
961 If the assimliated promise rejects, then the downstream promise will also reject.
964 findUser().then(function (user) {
965 return findCommentsByAuthor(user);
966 }).then(function (comments) {
967 // If `findCommentsByAuthor` fulfills, we'll have the value here
968 }, function (reason) {
969 // If `findCommentsByAuthor` rejects, we'll have the reason here
982 result = findResult();
992 findResult(function(result, err){
1004 findResult().then(function(result){
1006 }, function(reason){
1020 author = findAuthor();
1021 books = findBooksByAuthor(author);
1032 function foundBooks(books) {
1036 function failure(reason) {
1040 findAuthor(function(author, err){
1046 findBoooksByAuthor(author, function(books, err) {
1069 then(findBooksByAuthor).
1070 then(function(books){
1072 }).catch(function(reason){
1073 // something went wrong
1078 @param {Function} onFulfilled
1079 @param {Function} onRejected
1086 `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
1087 as the catch block of a try/catch statement.
1090 function findAuthor(){
1091 throw new Error('couldn't find that author');
1098 // something went wrong
1101 // async with promises
1102 findAuthor().catch(function(reason){
1103 // something went wrong
1108 @param {Function} onRejection
1112 'catch': function _catch(onRejection) {
1113 return this.then(null, onRejection);
1117 function polyfill() {
1118 var local = undefined;
1120 if (typeof global !== 'undefined') {
1122 } else if (typeof self !== 'undefined') {
1126 local = Function('return this')();
1128 throw new Error('polyfill failed because global object is unavailable in this environment');
1132 var P = local.Promise;
1135 var promiseToString = null;
1137 promiseToString = Object.prototype.toString.call(P.resolve());
1142 if (promiseToString === '[object Promise]' && !P.cast) {
1147 local.Promise = Promise;
1151 Promise.polyfill = polyfill;
1152 Promise.Promise = Promise;
1158 ES6Promise.polyfill();
1159 //# sourceMappingURL=es6-promise.auto.map