You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					293 lines
				
				5.8 KiB
			
		
		
			
		
	
	
					293 lines
				
				5.8 KiB
			| 
											3 years ago
										 | 'use strict'; | ||
|  | 
 | ||
|  | var PENDING = 'pending'; | ||
|  | var SETTLED = 'settled'; | ||
|  | var FULFILLED = 'fulfilled'; | ||
|  | var REJECTED = 'rejected'; | ||
|  | var NOOP = function () {}; | ||
|  | var isNode = typeof global !== 'undefined' && typeof global.process !== 'undefined' && typeof global.process.emit === 'function'; | ||
|  | 
 | ||
|  | var asyncSetTimer = typeof setImmediate === 'undefined' ? setTimeout : setImmediate; | ||
|  | var asyncQueue = []; | ||
|  | var asyncTimer; | ||
|  | 
 | ||
|  | function asyncFlush() { | ||
|  | 	// run promise callbacks
 | ||
|  | 	for (var i = 0; i < asyncQueue.length; i++) { | ||
|  | 		asyncQueue[i][0](asyncQueue[i][1]); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// reset async asyncQueue
 | ||
|  | 	asyncQueue = []; | ||
|  | 	asyncTimer = false; | ||
|  | } | ||
|  | 
 | ||
|  | function asyncCall(callback, arg) { | ||
|  | 	asyncQueue.push([callback, arg]); | ||
|  | 
 | ||
|  | 	if (!asyncTimer) { | ||
|  | 		asyncTimer = true; | ||
|  | 		asyncSetTimer(asyncFlush, 0); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | function invokeResolver(resolver, promise) { | ||
|  | 	function resolvePromise(value) { | ||
|  | 		resolve(promise, value); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function rejectPromise(reason) { | ||
|  | 		reject(promise, reason); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	try { | ||
|  | 		resolver(resolvePromise, rejectPromise); | ||
|  | 	} catch (e) { | ||
|  | 		rejectPromise(e); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | function invokeCallback(subscriber) { | ||
|  | 	var owner = subscriber.owner; | ||
|  | 	var settled = owner._state; | ||
|  | 	var value = owner._data; | ||
|  | 	var callback = subscriber[settled]; | ||
|  | 	var promise = subscriber.then; | ||
|  | 
 | ||
|  | 	if (typeof callback === 'function') { | ||
|  | 		settled = FULFILLED; | ||
|  | 		try { | ||
|  | 			value = callback(value); | ||
|  | 		} catch (e) { | ||
|  | 			reject(promise, e); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (!handleThenable(promise, value)) { | ||
|  | 		if (settled === FULFILLED) { | ||
|  | 			resolve(promise, value); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (settled === REJECTED) { | ||
|  | 			reject(promise, value); | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | function handleThenable(promise, value) { | ||
|  | 	var resolved; | ||
|  | 
 | ||
|  | 	try { | ||
|  | 		if (promise === value) { | ||
|  | 			throw new TypeError('A promises callback cannot return that same promise.'); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (value && (typeof value === 'function' || typeof value === 'object')) { | ||
|  | 			// then should be retrieved only once
 | ||
|  | 			var then = value.then; | ||
|  | 
 | ||
|  | 			if (typeof then === 'function') { | ||
|  | 				then.call(value, function (val) { | ||
|  | 					if (!resolved) { | ||
|  | 						resolved = true; | ||
|  | 
 | ||
|  | 						if (value === val) { | ||
|  | 							fulfill(promise, val); | ||
|  | 						} else { | ||
|  | 							resolve(promise, val); | ||
|  | 						} | ||
|  | 					} | ||
|  | 				}, function (reason) { | ||
|  | 					if (!resolved) { | ||
|  | 						resolved = true; | ||
|  | 
 | ||
|  | 						reject(promise, reason); | ||
|  | 					} | ||
|  | 				}); | ||
|  | 
 | ||
|  | 				return true; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} catch (e) { | ||
|  | 		if (!resolved) { | ||
|  | 			reject(promise, e); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return true; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return false; | ||
|  | } | ||
|  | 
 | ||
|  | function resolve(promise, value) { | ||
|  | 	if (promise === value || !handleThenable(promise, value)) { | ||
|  | 		fulfill(promise, value); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | function fulfill(promise, value) { | ||
|  | 	if (promise._state === PENDING) { | ||
|  | 		promise._state = SETTLED; | ||
|  | 		promise._data = value; | ||
|  | 
 | ||
|  | 		asyncCall(publishFulfillment, promise); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | function reject(promise, reason) { | ||
|  | 	if (promise._state === PENDING) { | ||
|  | 		promise._state = SETTLED; | ||
|  | 		promise._data = reason; | ||
|  | 
 | ||
|  | 		asyncCall(publishRejection, promise); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | function publish(promise) { | ||
|  | 	promise._then = promise._then.forEach(invokeCallback); | ||
|  | } | ||
|  | 
 | ||
|  | function publishFulfillment(promise) { | ||
|  | 	promise._state = FULFILLED; | ||
|  | 	publish(promise); | ||
|  | } | ||
|  | 
 | ||
|  | function publishRejection(promise) { | ||
|  | 	promise._state = REJECTED; | ||
|  | 	publish(promise); | ||
|  | 	if (!promise._handled && isNode) { | ||
|  | 		global.process.emit('unhandledRejection', promise._data, promise); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | function notifyRejectionHandled(promise) { | ||
|  | 	global.process.emit('rejectionHandled', promise); | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * @class | ||
|  |  */ | ||
|  | function Promise(resolver) { | ||
|  | 	if (typeof resolver !== 'function') { | ||
|  | 		throw new TypeError('Promise resolver ' + resolver + ' is not a function'); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (this instanceof Promise === false) { | ||
|  | 		throw new TypeError('Failed to construct \'Promise\': Please use the \'new\' operator, this object constructor cannot be called as a function.'); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	this._then = []; | ||
|  | 
 | ||
|  | 	invokeResolver(resolver, this); | ||
|  | } | ||
|  | 
 | ||
|  | Promise.prototype = { | ||
|  | 	constructor: Promise, | ||
|  | 
 | ||
|  | 	_state: PENDING, | ||
|  | 	_then: null, | ||
|  | 	_data: undefined, | ||
|  | 	_handled: false, | ||
|  | 
 | ||
|  | 	then: function (onFulfillment, onRejection) { | ||
|  | 		var subscriber = { | ||
|  | 			owner: this, | ||
|  | 			then: new this.constructor(NOOP), | ||
|  | 			fulfilled: onFulfillment, | ||
|  | 			rejected: onRejection | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		if ((onRejection || onFulfillment) && !this._handled) { | ||
|  | 			this._handled = true; | ||
|  | 			if (this._state === REJECTED && isNode) { | ||
|  | 				asyncCall(notifyRejectionHandled, this); | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (this._state === FULFILLED || this._state === REJECTED) { | ||
|  | 			// already resolved, call callback async
 | ||
|  | 			asyncCall(invokeCallback, subscriber); | ||
|  | 		} else { | ||
|  | 			// subscribe
 | ||
|  | 			this._then.push(subscriber); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return subscriber.then; | ||
|  | 	}, | ||
|  | 
 | ||
|  | 	catch: function (onRejection) { | ||
|  | 		return this.then(null, onRejection); | ||
|  | 	} | ||
|  | }; | ||
|  | 
 | ||
|  | Promise.all = function (promises) { | ||
|  | 	if (!Array.isArray(promises)) { | ||
|  | 		throw new TypeError('You must pass an array to Promise.all().'); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return new Promise(function (resolve, reject) { | ||
|  | 		var results = []; | ||
|  | 		var remaining = 0; | ||
|  | 
 | ||
|  | 		function resolver(index) { | ||
|  | 			remaining++; | ||
|  | 			return function (value) { | ||
|  | 				results[index] = value; | ||
|  | 				if (!--remaining) { | ||
|  | 					resolve(results); | ||
|  | 				} | ||
|  | 			}; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		for (var i = 0, promise; i < promises.length; i++) { | ||
|  | 			promise = promises[i]; | ||
|  | 
 | ||
|  | 			if (promise && typeof promise.then === 'function') { | ||
|  | 				promise.then(resolver(i), reject); | ||
|  | 			} else { | ||
|  | 				results[i] = promise; | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (!remaining) { | ||
|  | 			resolve(results); | ||
|  | 		} | ||
|  | 	}); | ||
|  | }; | ||
|  | 
 | ||
|  | Promise.race = function (promises) { | ||
|  | 	if (!Array.isArray(promises)) { | ||
|  | 		throw new TypeError('You must pass an array to Promise.race().'); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return new Promise(function (resolve, reject) { | ||
|  | 		for (var i = 0, promise; i < promises.length; i++) { | ||
|  | 			promise = promises[i]; | ||
|  | 
 | ||
|  | 			if (promise && typeof promise.then === 'function') { | ||
|  | 				promise.then(resolve, reject); | ||
|  | 			} else { | ||
|  | 				resolve(promise); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	}); | ||
|  | }; | ||
|  | 
 | ||
|  | Promise.resolve = function (value) { | ||
|  | 	if (value && typeof value === 'object' && value.constructor === Promise) { | ||
|  | 		return value; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return new Promise(function (resolve) { | ||
|  | 		resolve(value); | ||
|  | 	}); | ||
|  | }; | ||
|  | 
 | ||
|  | Promise.reject = function (reason) { | ||
|  | 	return new Promise(function (resolve, reject) { | ||
|  | 		reject(reason); | ||
|  | 	}); | ||
|  | }; | ||
|  | 
 | ||
|  | module.exports = Promise; |