3 var PENDING = 'pending';
4 var SETTLED = 'settled';
5 var FULFILLED = 'fulfilled';
6 var REJECTED = 'rejected';
7 var NOOP = function () {};
8 var isNode = typeof global !== 'undefined' && typeof global.process !== 'undefined' && typeof global.process.emit === 'function';
10 var asyncSetTimer = typeof setImmediate === 'undefined' ? setTimeout : setImmediate;
14 function asyncFlush() {
15 // run promise callbacks
16 for (var i = 0; i < asyncQueue.length; i++) {
17 asyncQueue[i][0](asyncQueue[i][1]);
20 // reset async asyncQueue
25 function asyncCall(callback, arg) {
26 asyncQueue.push([callback, arg]);
30 asyncSetTimer(asyncFlush, 0);
34 function invokeResolver(resolver, promise) {
35 function resolvePromise(value) {
36 resolve(promise, value);
39 function rejectPromise(reason) {
40 reject(promise, reason);
44 resolver(resolvePromise, rejectPromise);
50 function invokeCallback(subscriber) {
51 var owner = subscriber.owner;
52 var settled = owner._state;
53 var value = owner._data;
54 var callback = subscriber[settled];
55 var promise = subscriber.then;
57 if (typeof callback === 'function') {
60 value = callback(value);
66 if (!handleThenable(promise, value)) {
67 if (settled === FULFILLED) {
68 resolve(promise, value);
71 if (settled === REJECTED) {
72 reject(promise, value);
77 function handleThenable(promise, value) {
81 if (promise === value) {
82 throw new TypeError('A promises callback cannot return that same promise.');
85 if (value && (typeof value === 'function' || typeof value === 'object')) {
86 // then should be retrieved only once
87 var then = value.then;
89 if (typeof then === 'function') {
90 then.call(value, function (val) {
95 fulfill(promise, val);
97 resolve(promise, val);
100 }, function (reason) {
104 reject(promise, reason);
122 function resolve(promise, value) {
123 if (promise === value || !handleThenable(promise, value)) {
124 fulfill(promise, value);
128 function fulfill(promise, value) {
129 if (promise._state === PENDING) {
130 promise._state = SETTLED;
131 promise._data = value;
133 asyncCall(publishFulfillment, promise);
137 function reject(promise, reason) {
138 if (promise._state === PENDING) {
139 promise._state = SETTLED;
140 promise._data = reason;
142 asyncCall(publishRejection, promise);
146 function publish(promise) {
147 promise._then = promise._then.forEach(invokeCallback);
150 function publishFulfillment(promise) {
151 promise._state = FULFILLED;
155 function publishRejection(promise) {
156 promise._state = REJECTED;
158 if (!promise._handled && isNode) {
159 global.process.emit('unhandledRejection', promise._data, promise);
163 function notifyRejectionHandled(promise) {
164 global.process.emit('rejectionHandled', promise);
170 function Promise(resolver) {
171 if (typeof resolver !== 'function') {
172 throw new TypeError('Promise resolver ' + resolver + ' is not a function');
175 if (this instanceof Promise === false) {
176 throw new TypeError('Failed to construct \'Promise\': Please use the \'new\' operator, this object constructor cannot be called as a function.');
181 invokeResolver(resolver, this);
184 Promise.prototype = {
185 constructor: Promise,
192 then: function (onFulfillment, onRejection) {
195 then: new this.constructor(NOOP),
196 fulfilled: onFulfillment,
197 rejected: onRejection
200 if ((onRejection || onFulfillment) && !this._handled) {
201 this._handled = true;
202 if (this._state === REJECTED && isNode) {
203 asyncCall(notifyRejectionHandled, this);
207 if (this._state === FULFILLED || this._state === REJECTED) {
208 // already resolved, call callback async
209 asyncCall(invokeCallback, subscriber);
212 this._then.push(subscriber);
215 return subscriber.then;
218 catch: function (onRejection) {
219 return this.then(null, onRejection);
223 Promise.all = function (promises) {
224 if (!Array.isArray(promises)) {
225 throw new TypeError('You must pass an array to Promise.all().');
228 return new Promise(function (resolve, reject) {
232 function resolver(index) {
234 return function (value) {
235 results[index] = value;
242 for (var i = 0, promise; i < promises.length; i++) {
243 promise = promises[i];
245 if (promise && typeof promise.then === 'function') {
246 promise.then(resolver(i), reject);
248 results[i] = promise;
258 Promise.race = function (promises) {
259 if (!Array.isArray(promises)) {
260 throw new TypeError('You must pass an array to Promise.race().');
263 return new Promise(function (resolve, reject) {
264 for (var i = 0, promise; i < promises.length; i++) {
265 promise = promises[i];
267 if (promise && typeof promise.then === 'function') {
268 promise.then(resolve, reject);
276 Promise.resolve = function (value) {
277 if (value && typeof value === 'object' && value.constructor === Promise) {
281 return new Promise(function (resolve) {
286 Promise.reject = function (reason) {
287 return new Promise(function (resolve, reject) {
292 module.exports = Promise;