UNPKG

5.97 kBJavaScriptView Raw
1(function (root) {
2
3 // Store setTimeout reference so promise-polyfill will be unaffected by
4 // other code modifying setTimeout (like sinon.useFakeTimers())
5 var setTimeoutFunc = setTimeout;
6
7 function noop() {
8 }
9
10 // Use polyfill for setImmediate for performance gains
11 var asap = (typeof setImmediate === 'function' && setImmediate) ||
12 function (fn) {
13 setTimeoutFunc(fn, 0);
14 };
15
16 var onUnhandledRejection = function onUnhandledRejection(err) {
17 if (typeof console !== 'undefined' && console) {
18 console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
19 }
20 };
21
22 // Polyfill for Function.prototype.bind
23 function bind(fn, thisArg) {
24 return function () {
25 fn.apply(thisArg, arguments);
26 };
27 }
28
29 function Promise(fn) {
30 if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
31 if (typeof fn !== 'function') throw new TypeError('not a function');
32 this._state = 0;
33 this._handled = false;
34 this._value = undefined;
35 this._deferreds = [];
36
37 doResolve(fn, this);
38 }
39
40 function handle(self, deferred) {
41 while (self._state === 3) {
42 self = self._value;
43 }
44 if (self._state === 0) {
45 self._deferreds.push(deferred);
46 return;
47 }
48 self._handled = true;
49 asap(function () {
50 var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
51 if (cb === null) {
52 (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
53 return;
54 }
55 var ret;
56 try {
57 ret = cb(self._value);
58 } catch (e) {
59 reject(deferred.promise, e);
60 return;
61 }
62 resolve(deferred.promise, ret);
63 });
64 }
65
66 function resolve(self, newValue) {
67 try {
68 // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
69 if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.');
70 if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
71 var then = newValue.then;
72 if (newValue instanceof Promise) {
73 self._state = 3;
74 self._value = newValue;
75 finale(self);
76 return;
77 } else if (typeof then === 'function') {
78 doResolve(bind(then, newValue), self);
79 return;
80 }
81 }
82 self._state = 1;
83 self._value = newValue;
84 finale(self);
85 } catch (e) {
86 reject(self, e);
87 }
88 }
89
90 function reject(self, newValue) {
91 self._state = 2;
92 self._value = newValue;
93 finale(self);
94 }
95
96 function finale(self) {
97 if (self._state === 2 && self._deferreds.length === 0) {
98 asap(function() {
99 if (!self._handled) {
100 onUnhandledRejection(self._value);
101 }
102 });
103 }
104
105 for (var i = 0, len = self._deferreds.length; i < len; i++) {
106 handle(self, self._deferreds[i]);
107 }
108 self._deferreds = null;
109 }
110
111 function Handler(onFulfilled, onRejected, promise) {
112 this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
113 this.onRejected = typeof onRejected === 'function' ? onRejected : null;
114 this.promise = promise;
115 }
116
117 /**
118 * Take a potentially misbehaving resolver function and make sure
119 * onFulfilled and onRejected are only called once.
120 *
121 * Makes no guarantees about asynchrony.
122 */
123 function doResolve(fn, self) {
124 var done = false;
125 try {
126 fn(function (value) {
127 if (done) return;
128 done = true;
129 resolve(self, value);
130 }, function (reason) {
131 if (done) return;
132 done = true;
133 reject(self, reason);
134 });
135 } catch (ex) {
136 if (done) return;
137 done = true;
138 reject(self, ex);
139 }
140 }
141
142 Promise.prototype['catch'] = function (onRejected) {
143 return this.then(null, onRejected);
144 };
145
146 Promise.prototype.then = function (onFulfilled, onRejected) {
147 var prom = new (this.constructor)(noop);
148
149 handle(this, new Handler(onFulfilled, onRejected, prom));
150 return prom;
151 };
152
153 Promise.all = function (arr) {
154 var args = Array.prototype.slice.call(arr);
155
156 return new Promise(function (resolve, reject) {
157 if (args.length === 0) return resolve([]);
158 var remaining = args.length;
159
160 function res(i, val) {
161 try {
162 if (val && (typeof val === 'object' || typeof val === 'function')) {
163 var then = val.then;
164 if (typeof then === 'function') {
165 then.call(val, function (val) {
166 res(i, val);
167 }, reject);
168 return;
169 }
170 }
171 args[i] = val;
172 if (--remaining === 0) {
173 resolve(args);
174 }
175 } catch (ex) {
176 reject(ex);
177 }
178 }
179
180 for (var i = 0; i < args.length; i++) {
181 res(i, args[i]);
182 }
183 });
184 };
185
186 Promise.resolve = function (value) {
187 if (value && typeof value === 'object' && value.constructor === Promise) {
188 return value;
189 }
190
191 return new Promise(function (resolve) {
192 resolve(value);
193 });
194 };
195
196 Promise.reject = function (value) {
197 return new Promise(function (resolve, reject) {
198 reject(value);
199 });
200 };
201
202 Promise.race = function (values) {
203 return new Promise(function (resolve, reject) {
204 for (var i = 0, len = values.length; i < len; i++) {
205 values[i].then(resolve, reject);
206 }
207 });
208 };
209
210 /**
211 * Set the immediate function to execute callbacks
212 * @param fn {function} Function to execute
213 * @private
214 */
215 Promise._setImmediateFn = function _setImmediateFn(fn) {
216 asap = fn;
217 };
218
219 Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
220 onUnhandledRejection = fn;
221 };
222
223 if (typeof module !== 'undefined' && module.exports) {
224 module.exports = Promise;
225 } else if (!root.Promise) {
226 root.Promise = Promise;
227 }
228
229})(this);