UNPKG

7.84 kBJavaScriptView Raw
1
2// PhantomJS doesn't support bind yet
3// https://github.com/ariya/phantomjs/issues/10522
4
5Function.prototype.bind = Function.prototype.bind || function (thisp) {
6 var fn = this;
7 return function () {
8 return fn.apply(thisp, arguments);
9 };
10};
11
12/* eslint-disable */
13// https://raw.githubusercontent.com/lahmatiy/es6-promise-polyfill/master/promise.js
14(function(global){
15
16//
17// Check for native Promise and it has correct interface
18//
19
20var NativePromise = global['Promise'];
21var nativePromiseSupported =
22 NativePromise &&
23 // Some of these methods are missing from
24 // Firefox/Chrome experimental implementations
25 'resolve' in NativePromise &&
26 'reject' in NativePromise &&
27 'all' in NativePromise &&
28 'race' in NativePromise &&
29 // Older version of the spec had a resolver object
30 // as the arg rather than a function
31 (function(){
32 var resolve;
33 new NativePromise(function(r){ resolve = r; });
34 return typeof resolve === 'function';
35 })();
36
37
38//
39// export if necessary
40//
41
42if (typeof exports !== 'undefined' && exports)
43{
44 // node.js
45 exports.Promise = nativePromiseSupported ? NativePromise : Promise;
46 exports.Polyfill = Promise;
47}
48else
49{
50 // AMD
51 if (typeof define == 'function' && define.amd)
52 {
53 define(function(){
54 return nativePromiseSupported ? NativePromise : Promise;
55 });
56 }
57 else
58 {
59 // in browser add to global
60 if (!nativePromiseSupported)
61 global['Promise'] = Promise;
62 }
63}
64
65
66//
67// Polyfill
68//
69
70var PENDING = 'pending';
71var SEALED = 'sealed';
72var FULFILLED = 'fulfilled';
73var REJECTED = 'rejected';
74var NOOP = function(){};
75
76function isArray(value) {
77 return Object.prototype.toString.call(value) === '[object Array]';
78}
79
80// async calls
81var asyncSetTimer = typeof setImmediate !== 'undefined' ? setImmediate : setTimeout;
82var asyncQueue = [];
83var asyncTimer;
84
85function asyncFlush(){
86 // run promise callbacks
87 for (var i = 0; i < asyncQueue.length; i++)
88 asyncQueue[i][0](asyncQueue[i][1]);
89
90 // reset async asyncQueue
91 asyncQueue = [];
92 asyncTimer = false;
93}
94
95function asyncCall(callback, arg){
96 asyncQueue.push([callback, arg]);
97
98 if (!asyncTimer)
99 {
100 asyncTimer = true;
101 asyncSetTimer(asyncFlush, 0);
102 }
103}
104
105
106function invokeResolver(resolver, promise) {
107 function resolvePromise(value) {
108 resolve(promise, value);
109 }
110
111 function rejectPromise(reason) {
112 reject(promise, reason);
113 }
114
115 try {
116 resolver(resolvePromise, rejectPromise);
117 } catch(e) {
118 rejectPromise(e);
119 }
120}
121
122function invokeCallback(subscriber){
123 var owner = subscriber.owner;
124 var settled = owner.state_;
125 var value = owner.data_;
126 var callback = subscriber[settled];
127 var promise = subscriber.then;
128
129 if (typeof callback === 'function')
130 {
131 settled = FULFILLED;
132 try {
133 value = callback(value);
134 } catch(e) {
135 reject(promise, e);
136 }
137 }
138
139 if (!handleThenable(promise, value))
140 {
141 if (settled === FULFILLED)
142 resolve(promise, value);
143
144 if (settled === REJECTED)
145 reject(promise, value);
146 }
147}
148
149function handleThenable(promise, value) {
150 var resolved;
151
152 try {
153 if (promise === value)
154 throw new TypeError('A promises callback cannot return that same promise.');
155
156 if (value && (typeof value === 'function' || typeof value === 'object'))
157 {
158 var then = value.then; // then should be retrived only once
159
160 if (typeof then === 'function')
161 {
162 then.call(value, function(val){
163 if (!resolved)
164 {
165 resolved = true;
166
167 if (value !== val)
168 resolve(promise, val);
169 else
170 fulfill(promise, val);
171 }
172 }, function(reason){
173 if (!resolved)
174 {
175 resolved = true;
176
177 reject(promise, reason);
178 }
179 });
180
181 return true;
182 }
183 }
184 } catch (e) {
185 if (!resolved)
186 reject(promise, e);
187
188 return true;
189 }
190
191 return false;
192}
193
194function resolve(promise, value){
195 if (promise === value || !handleThenable(promise, value))
196 fulfill(promise, value);
197}
198
199function fulfill(promise, value){
200 if (promise.state_ === PENDING)
201 {
202 promise.state_ = SEALED;
203 promise.data_ = value;
204
205 asyncCall(publishFulfillment, promise);
206 }
207}
208
209function reject(promise, reason){
210 if (promise.state_ === PENDING)
211 {
212 promise.state_ = SEALED;
213 promise.data_ = reason;
214
215 asyncCall(publishRejection, promise);
216 }
217}
218
219function publish(promise) {
220 var callbacks = promise.then_;
221 promise.then_ = undefined;
222
223 for (var i = 0; i < callbacks.length; i++) {
224 invokeCallback(callbacks[i]);
225 }
226}
227
228function publishFulfillment(promise){
229 promise.state_ = FULFILLED;
230 publish(promise);
231}
232
233function publishRejection(promise){
234 promise.state_ = REJECTED;
235 publish(promise);
236}
237
238/**
239* @class
240*/
241function Promise(resolver){
242 if (typeof resolver !== 'function')
243 throw new TypeError('Promise constructor takes a function argument');
244
245 if (this instanceof Promise === false)
246 throw new TypeError('Failed to construct \'Promise\': Please use the \'new\' operator, this object constructor cannot be called as a function.');
247
248 this.then_ = [];
249
250 invokeResolver(resolver, this);
251}
252
253Promise.prototype = {
254 constructor: Promise,
255
256 state_: PENDING,
257 then_: null,
258 data_: undefined,
259
260 then: function(onFulfillment, onRejection){
261 var subscriber = {
262 owner: this,
263 then: new this.constructor(NOOP),
264 fulfilled: onFulfillment,
265 rejected: onRejection
266 };
267
268 if (this.state_ === FULFILLED || this.state_ === REJECTED)
269 {
270 // already resolved, call callback async
271 asyncCall(invokeCallback, subscriber);
272 }
273 else
274 {
275 // subscribe
276 this.then_.push(subscriber);
277 }
278
279 return subscriber.then;
280 },
281
282 'catch': function(onRejection) {
283 return this.then(null, onRejection);
284 }
285};
286
287Promise.all = function(promises){
288 var Class = this;
289
290 if (!isArray(promises))
291 throw new TypeError('You must pass an array to Promise.all().');
292
293 return new Class(function(resolve, reject){
294 var results = [];
295 var remaining = 0;
296
297 function resolver(index){
298 remaining++;
299 return function(value){
300 results[index] = value;
301 if (!--remaining)
302 resolve(results);
303 };
304 }
305
306 for (var i = 0, promise; i < promises.length; i++)
307 {
308 promise = promises[i];
309
310 if (promise && typeof promise.then === 'function')
311 promise.then(resolver(i), reject);
312 else
313 results[i] = promise;
314 }
315
316 if (!remaining)
317 resolve(results);
318 });
319};
320
321Promise.race = function(promises){
322 var Class = this;
323
324 if (!isArray(promises))
325 throw new TypeError('You must pass an array to Promise.race().');
326
327 return new Class(function(resolve, reject) {
328 for (var i = 0, promise; i < promises.length; i++)
329 {
330 promise = promises[i];
331
332 if (promise && typeof promise.then === 'function')
333 promise.then(resolve, reject);
334 else
335 resolve(promise);
336 }
337 });
338};
339
340Promise.resolve = function(value){
341 var Class = this;
342
343 if (value && typeof value === 'object' && value.constructor === Class)
344 return value;
345
346 return new Class(function(resolve){
347 resolve(value);
348 });
349};
350
351Promise.reject = function(reason){
352 var Class = this;
353
354 return new Class(function(resolve, reject){
355 reject(reason);
356 });
357};
358
359})(typeof window != 'undefined' ? window : typeof global != 'undefined' ? global : typeof self != 'undefined' ? self : this);