promise的实现
Posted oxspirt
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了promise的实现相关的知识,希望对你有一定的参考价值。
原文:https://blog.csdn.net/sinat_17775997/article/details/70170939
----------------------------------------
本文缘起前段时间一朋友换工作时,笔试题中要求手写一个Promise。在工作中虽已大量使用Promise,其原理却没有深入探究过,换做自己,当场也很难手写一个完善的Promise实现。近期补了一些课,以本文来彻底的理解Promise实现原理。
http://www.jianshu.com/p/f8b052c71550
1.Promise是什么
Promise是抽象异步处理对象以及对其进行各种操作的组件,可以将复杂的异步处理轻松的进行模式化。
使用Promise进行异步处理的一个例子
如对Promise的使用尚不了解,推荐阅读JavaScript Promise Cookbook中文版
---------------------
https://github.com/bruce-xu/Promise/blob/master/Promise.js
/** * @file JS Promise实现 * @author bruxexyj@gmail.com */ (function (factory, global) { if (typeof define === ‘function‘ && define.amd) { define(factory); } else if (typeof module === ‘object‘ && module.exports) { module.exports = exports = factory(); } else { global.Promise = factory(); } }(function () { /** * Promise对象的内部状态 * * @type {Object} */ var Status = { PENDING: ‘pending‘, FULLFILLED: ‘resolved‘, REJECTED: ‘rejected‘ }; function empty() {} /** * Promise构造函数 * * @constructor * @param {Function} resolver 此Promise对象管理的任务 */ function Promise(resolver) { // ES6原生的Promise构造函数中,若不通过`new`调用Promise的构造函数,会抛出TypeError异常。此处与其一致 if (!(this instanceof Promise)) { throw new TypeError(‘TypeError: undefined is not a promise‘); } // ES6原生的Promise构造函数中,若无作为函数的resolver参数,会抛出TypeError异常。此处与其一致 if (typeof resolver !== ‘function‘) { throw new TypeError(‘TypeError: Promise resolver undefined is not a function‘); } /** * Promise对象内部的状态,初始为`pending`。状态只能由`pending`到`fullfilled`或`rejected` * * @type {string} */ this._status = Status.PENDING; /** * Promise对象resolved/rejected后拥有的data/reason * * - 此处保存此值是为了当一个Promise对象被resolved或rejected后,继续对其调用`then`添加任务,后续处理仍能获得当前Promise的值 * * @type {Mixed} */ this._value; /** * 当前Promise被resolved/rejected后,需处理的任务 * * - 由于同一个Promise对象可以调用多次`then`方法,以添加多个并行任务,所以此处是一个数组 * * @type {Array.<Function>} */ this._doneCallbacks = []; this._failCallbacks = []; var promise = this; resolver( function (data) { resolve(promise, data); }, function (reason) { reject(promise, reason); } ); } Promise.prototype = { constructor: Promise, /** * Promise的`then`方法 * * @param {Function|Mixed} onResolve 当前Promise对象被resolved后,需处理的任务 * @param {Function|Mixed} onReject 当前Promise对象被rejected后,需处理的任务 * @return {Promise} 返回一个新的Promise对象,用于链式操作 */ then: function (onResolve, onReject) { var promise = new Promise(empty); this._doneCallbacks.push(makeCallback(promise, onResolve, ‘resolve‘)); this._failCallbacks.push(makeCallback(promise, onReject, ‘reject‘)); // 如果在一个已经被fullfilled或rejected的promise上调用then,则需要直接执行通过then注册的回调函数 run(this); return promise; }, /** * Promise的`done`方法 * * @param {Function|Mixed} onResolve 当前Promise对象被resolved后,需处理的任务 * @return {Promise} 返回一个新的Promise对象,用于链式操作 */ done: function (onResolve) { return this.then(onResolve, null); }, /** * Promise的`fail`方法 * * @param {Function|Mixed} onReject 当前Promise对象被rejected后,需处理的任务 * @return {Promise} 返回一个新的Promise对象,用于链式操作 */ fail: function (onReject) { return this.then(null, onReject); }, /** * Promise的`catch`方法 * * @param {Function|Mixed} onFail 当前Promise对象被rejected后,需处理的任务 * @return {Promise} 返回一个新的Promise对象,用于链式操作 */ catch: function (onFail) { return this.then(null, onFail); } }; /** * 创建一个Promise对象,并用给定值resolve它 * * @param {Mixed} value 用于resolve新创建的Promise对象的值 * @return {Promise} 返回一个新的Promise对象,用于链式操作 */ Promise.resolve = function (value) { var promise = new Promise(empty); resolve(promise, value); return promise; }; /** * 创建一个Promise对象,并用给定值reject它 * * @param {Mixed} reason 用于reject新创建的Promise对象的值 * @return {Promise} 返回一个新的Promise对象,用于链式操作 */ Promise.reject = function (reason) { var promise = new Promise(empty); reject(promise, reason); return promise; }; /** * 返回一个promise,这个promise在iterable中的任意一个promise被解决或拒绝后, * 立刻以相同的解决值被解决或以相同的拒绝原因被拒绝 * * @param {Iterable.<Promise|Mixed>} iterable 一组Promise对象或其它值 * @return {Promise} 返回一个新的Promise对象,用于链式操作 */ Promise.race = function (iterable) { if (!iterable || !iterable.hasOwnProperty(‘length‘)) { throw new TypeError(‘TypeError: Parameter `iterable` must be a iterable object‘); } var promise = new Promise(empty); for (var i = 0, len = iterable.length; i < len; i++) { var iterate = iterable[i]; if (!(iterate instanceof Promise)) { iterate = Promise.resolve(iterate); } iterate.then(resolveRaceCallback, rejectRaceCallback); } var settled = false; function resolveRaceCallback(data) { if (settled) { return; } settled = true; resolve(promise, data); } function rejectRaceCallback(reason) { if (settled) { return; } settled = true; reject(promise, reason); } }; /** * 返回一个promise,该promise会在iterable参数内的所有promise都被解决后被解决 * * @param {Iterable.<Promise|Mixed>} iterable 一组Promise对象或其它值 * @return {Promise} 返回一个新的Promise对象,用于链式操作 */ Promise.all = function (iterable) { if (!iterable || !iterable.hasOwnProperty(‘length‘)) { throw new TypeError(‘TypeError: Parameter `iterable` must be a iterable object‘); } var promise = new Promise(empty); var length = iterable.length; for (var i = 0; i < length; i++) { var iterate = iterable[i]; if (!(iterate instanceof Promise)) { iterate = Promise.resolve(iterate); } iterate.then(makeAllCallback(iterate, i, ‘resolve‘), makeAllCallback(iterate, i, ‘reject‘)); } var result = []; var count = 0; function makeAllCallback(iterate, index, action) { return function (value) { if (action === ‘reject‘) { reject(promise, value); return; } result[index] = value; if (++count === length) { resolve(promise, result); } } } }; /** * 返回一个Deferred对象,包含一个新创建的Promise对象,以及`resolve`和`reject`方法 * * @return {Deferred} */ Promise.defer = function () { var promise = new Promise(empty); return { promise: promise, resolve: function (data) { resolve(promise, data); }, reject: function (reason) { reject(promise, reason); } }; }; function run(promise) { // `then`方法中也会调用,所以此处仍需做一次判断 if (promise._status === Status.PENDING) { return; } var value = promise._value; var callbacks = promise._status === Status.FULLFILLED ? promise._doneCallbacks : promise._failCallbacks; // Promise需要异步操作 setTimeout(function () { for (var i = 0, len = callbacks.length; i < len; i++) { callbacks[i](value); } }); // 每个promise只能被执行一次。虽然`_doneCallbacks`和`_failCallbacks`用户不应该直接访问, // 但还是可以访问到,保险起见,做清空处理。 promise._doneCallbacks = []; promise._failCallbacks = []; } function resolve(promise, data) { if (promise._status !== Status.PENDING) { return; } promise._status = Status.FULLFILLED; promise._value = data; run(promise); } function reject(promise, reason) { if (promise._status !== Status.PENDING) { return; } promise._status = Status.REJECTED; promise._value = reason; run(promise); } function makeCallback(promise, callback, action) { return function promiseCallback(value) { // 如果传递了callback,则使用前一个promise传递过来的值作为参数调用callback, // 并根据callback的调用结果来处理当前promise if (typeof callback === ‘function‘) { var x; try { x = callback(value); } catch (e) { // 如果调用callback时抛出异常,则直接用此异常对象reject当前promise reject(promise, e); } // 如果callback的返回值是当前promise,为避免造成死循环,需要抛出异常 // 根据Promise+规范,此处应抛出TypeError异常 if (x === promise) { var reason = new TypeError(‘TypeError: The return value could not be same with the promise‘); reject(promise, reason); } // 如果返回值是一个Promise对象,则当返回的Promise对象被resolve/reject后,再resolve/reject当前Promise else if (x instanceof Promise) { x.then( function (data) { resolve(promise, data); }, function (reason) { reject(promise, reason); } ); } else { var then; (function resolveThenable(x) { // 如果返回的是一个Thenable对象(此处逻辑有点坑,参照Promise+的规范实现) if (x && (typeof x === ‘object‘|| typeof x === ‘function‘)) { try { then = x.then; } catch (e) { reject(promise, e); return; } if (typeof then === ‘function‘) { // 调用Thenable对象的`then`方法时,传递进去的`resolvePromise`和`rejectPromise`方法(及下面的两个匿名方法) // 可能会被重复调用。但Promise+规范规定这两个方法有且只能有其中的一个被调用一次,多次调用将被忽略。 // 此处通过`invoked`来处理重复调用 var invoked = false; try { then.call( x, function (y) { if (invoked) { return; } invoked = true; // 避免死循环 if (y === x) { throw new TypeError(‘TypeError: The return value could not be same with the previous thenable object‘); } // y仍有可能是thenable对象,递归调用 resolveThenable(y); }, function (e) { if (invoked) { return; } invoked = true; reject(promise, e); } ); } catch (e) { // 如果`resolvePromise`和`rejectPromise`方法被调用后,再抛出异常,则忽略异常 // 否则用异常对象reject此Promise对象 if (!invoked) { reject(promise, e); } } } else { resolve(promise, x); } } else { resolve(promise, x); } }(x)); } } // 如果未传递callback,直接用前一个promise传递过来的值resolve/reject当前Promise对象 else { action === ‘resolve‘ ? resolve(promise, value) : reject(promise, value); } }; } return Promise; }, this));
/** | |
* @file JS Promise实现 | |
* @author bruxexyj@gmail.com | |
*/ | |
(function (factory, global) { | |
if (typeof define === ‘function‘ && define.amd) { | |
define(factory); | |
} | |
else if (typeof module === ‘object‘ && module.exports) { | |
module.exports = exports = factory(); | |
} | |
else { | |
global.Promise = factory(); | |
} | |
}(function () { | |
/** | |
* Promise对象的内部状态 | |
* | |
* @type {Object} | |
*/ | |
var Status = { | |
PENDING: ‘pending‘, | |
FULLFILLED: ‘resolved‘, | |
REJECTED: ‘rejected‘ | |
}; | |
function empty() {} | |
/** | |
* Promise构造函数 | |
* | |
* @constructor | |
* @param {Function} resolver 此Promise对象管理的任务 | |
*/ | |
function Promise(resolver) { | |
// ES6原生的Promise构造函数中,若不通过`new`调用Promise的构造函数,会抛出TypeError异常。此处与其一致 | |
if (!(this instanceof Promise)) { | |
throw new TypeError(‘TypeError: undefined is not a promise‘); | |
} | |
// ES6原生的Promise构造函数中,若无作为函数的resolver参数,会抛出TypeError异常。此处与其一致 | |
if (typeof resolver !== ‘function‘) { | |
throw new TypeError(‘TypeError: Promise resolver undefined is not a function‘); | |
} | |
/** | |
* Promise对象内部的状态,初始为`pending`。状态只能由`pending`到`fullfilled`或`rejected` | |
* | |
* @type {string} | |
*/ | |
this._status = Status.PENDING; | |
/** | |
* Promise对象resolved/rejected后拥有的data/reason | |
* | |
* - 此处保存此值是为了当一个Promise对象被resolved或rejected后,继续对其调用`then`添加任务,后续处理仍能获得当前Promise的值 | |
* | |
* @type {Mixed} | |
*/ | |
this._value; | |
/** | |
* 当前Promise被resolved/rejected后,需处理的任务 | |
* | |
* - 由于同一个Promise对象可以调用多次`then`方法,以添加多个并行任务,所以此处是一个数组 | |
* | |
* @type {Array.<Function>} | |
*/ | |
this._doneCallbacks = []; | |
this._failCallbacks = []; | |
var promise = this; | |
resolver( | |
function (data) { | |
resolve(promise, data); | |
}, | |
function (reason) { | |
reject(promise, reason); | |
} | |
); | |
} | |
Promise.prototype = { | |
constructor: Promise, | |
/** | |
* Promise的`then`方法 | |
* | |
* @param {Function|Mixed} onResolve 当前Promise对象被resolved后,需处理的任务 | |
* @param {Function|Mixed} onReject 当前Promise对象被rejected后,需处理的任务 | |
* @return {Promise} 返回一个新的Promise对象,用于链式操作 | |
*/ | |
then: function (onResolve, onReject) { | |
var promise = new Promise(empty); | |
this._doneCallbacks.push(makeCallback(promise, onResolve, ‘resolve‘)); | |
this._failCallbacks.push(makeCallback(promise, onReject, ‘reject‘)); | |
// 如果在一个已经被fullfilled或rejected的promise上调用then,则需要直接执行通过then注册的回调函数 | |
run(this); | |
return promise; | |
}, | |
/** | |
* Promise的`done`方法 | |
* | |
* @param {Function|Mixed} onResolve 当前Promise对象被resolved后,需处理的任务 | |
* @return {Promise} 返回一个新的Promise对象,用于链式操作 | |
*/ | |
done: function (onResolve) { | |
return this.then(onResolve, null); | |
}, | |
/** | |
* Promise的`fail`方法 | |
* | |
* @param {Function|Mixed} onReject 当前Promise对象被rejected后,需处理的任务 | |
* @return {Promise} 返回一个新的Promise对象,用于链式操作 | |
*/ | |
fail: function (onReject) { | |
return this.then(null, onReject); | |
}, | |
/** | |
* Promise的`catch`方法 | |
* | |
* @param {Function|Mixed} onFail 当前Promise对象被rejected后,需处理的任务 | |
* @return {Promise} 返回一个新的Promise对象,用于链式操作 | |
*/ | |
catch: function (onFail) { | |
return this.then(null, onFail); | |
} | |
}; | |
/** | |
* 创建一个Promise对象,并用给定值resolve它 | |
* | |
* @param {Mixed} value 用于resolve新创建的Promise对象的值 | |
* @return {Promise} 返回一个新的Promise对象,用于链式操作 | |
*/ | |
Promise.resolve = function (value) { | |
var promise = new Promise(empty); | |
resolve(promise, value); | |
return promise; | |
}; | |
/** | |
* 创建一个Promise对象,并用给定值reject它 | |
* | |
* @param {Mixed} reason 用于reject新创建的Promise对象的值 | |
* @return {Promise} 返回一个新的Promise对象,用于链式操作 | |
*/ | |
Promise.reject = function (reason) { | |
var promise = new Promise(empty); | |
reject(promise, reason); | |
return promise; | |
}; | |
/** | |
* 返回一个promise,这个promise在iterable中的任意一个promise被解决或拒绝后, | |
* 立刻以相同的解决值被解决或以相同的拒绝原因被拒绝 | |
* | |
* @param {Iterable.<Promise|Mixed>} iterable 一组Promise对象或其它值 | |
* @return {Promise} 返回一个新的Promise对象,用于链式操作 | |
*/ | |
Promise.race = function (iterable) { | |
if (!iterable || !iterable.hasOwnProperty(‘length‘)) { | |
throw new TypeError(‘TypeError: Parameter `iterable` must be a iterable object‘); | |
} | |
var promise = new Promise(empty); | |
for (var i = 0, len = iterable.length; i < len; i++) { | |
var iterate = iterable[i]; | |
if (!(iterate instanceof Promise)) { | |
iterate = Promise.resolve(iterate); | |
} | |
iterate.then(resolveRaceCallback, rejectRaceCallback); | |
} | |
var settled = false; | |
function resolveRaceCallback(data) { | |
if (settled) { | |
return; | |
} | |
settled = true; | |
resolve(promise, data); | |
} | |
function rejectRaceCallback(reason) { | |
if (settled) { | |
return; | |
} | |
settled = true; | |
reject(promise, reason); | |
} | |
}; | |
/** | |
* 返回一个promise,该promise会在iterable参数内的所有promise都被解决后被解决 | |
* | |
* @param {Iterable.<Promise|Mixed>} iterable 一组Promise对象或其它值 | |
* @return {Promise} 返回一个新的Promise对象,用于链式操作 | |
*/ | |
Promise.all = function (iterable) { | |
if (!iterable || !iterable.hasOwnProperty(‘length‘)) { | |
throw new TypeError(‘TypeError: Parameter `iterable` must be a iterable object‘); | |
} | |
var promise = new Promise(empty); | |
var length = iterable.length; | |
for (var i = 0; i < length; i++) { | |
var iterate = iterable[i]; | |
if (!(iterate instanceof Promise)) { | |
iterate = Promise.resolve(iterate); | |
} | |
iterate.then(makeAllCallback(iterate, i, ‘resolve‘), makeAllCallback(iterate, i, ‘reject‘)); | |
} | |
var result = []; | |
var count = 0; | |
function makeAllCallback(iterate, index, action) { | |
return function (value) { | |
if (action === ‘reject‘) { | |
reject(promise, value); | |
return; | |
} | |
result[index] = value; | |
if (++count === length) { | |
resolve(promise, result); | |
} | |
} | |
} | |
}; | |
/** | |
* 返回一个Deferred对象,包含一个新创建的Promise对象,以及`resolve`和`reject`方法 | |
* | |
* @return {Deferred} | |
*/ | |
Promise.defer = function () { | |
var promise = new Promise(empty); | |
return { | |
promise: promise, | |
resolve: function (data) { | |
resolve(promise, data); | |
}, | |
reject: function (reason) { | |
reject(promise, reason); | |
} | |
}; | |
}; | |
function run(promise) { | |
// `then`方法中也会调用,所以此处仍需做一次判断 | |
if (promise._status === Status.PENDING) { | |
return; | |
} | |
var value = promise._value; | |
var callbacks = promise._status === Status.FULLFILLED | |
? promise._doneCallbacks | |
: promise._failCallbacks; | |
// Promise需要异步操作 | |
setTimeout(function () { | |
for (var i = 0, len = callbacks.length; i < len; i++) { | |
callbacks[i](value); | |
} | |
}); | |
// 每个promise只能被执行一次。虽然`_doneCallbacks`和`_failCallbacks`用户不应该直接访问, | |
// 但还是可以访问到,保险起见,做清空处理。 | |
promise._doneCallbacks = []; | |
promise._failCallbacks = []; | |
} | |
function resolve(promise, data) { | |
if (promise._status !== Status.PENDING) { | |
return; | |
} | |
promise._status = Status.FULLFILLED; | |
promise._value = data; | |
run(promise); | |
} | |
function reject(promise, reason) { | |
if (promise._status !== Status.PENDING) { | |
return; | |
} | |
promise._status = Status.REJECTED; | |
promise._value = reason; | |
run(promise); | |
} | |
function makeCallback(promise, callback, action) { | |
return function promiseCallback(value) { | |
// 如果传递了callback,则使用前一个promise传递过来的值作为参数调用callback, | |
// 并根据callback的调用结果来处理当前promise | |
if (typeof callback === ‘function‘) { | |
var x; | |
try { | |
x = callback(value); | |
} | |
catch (e) { | |
// 如果调用callback时抛出异常,则直接用此异常对象reject当前promise | |
reject(promise, e); | |
} | |
// 如果callback的返回值是当前promise,为避免造成死循环,需要抛出异常 | |
// 根据Promise+规范,此处应抛出TypeError异常 | |
if (x === promise) { | |
var reason = new TypeError(‘TypeError: The return value could not be same with the promise‘); | |
reject(promise, reason); | |
} | |
// 如果返回值是一个Promise对象,则当返回的Promise对象被resolve/reject后,再resolve/reject当前Promise | |
else if (x instanceof Promise) { | |
x.then( | |
function (data) { | |
resolve(promise, data); | |
}, | |
function (reason) { | |
reject(promise, reason); | |
} | |
); | |
} | |
else { | |
var then; | |
(function resolveThenable(x) { | |
// 如果返回的是一个Thenable对象(此处逻辑有点坑,参照Promise+的规范实现) | |
if (x && (typeof x === ‘object‘|| typeof x === ‘function‘)) { | |
try { | |
then = x.then; | |
} | |
catch (e) { | |
reject(promise, e); | |
return; | |
} | |
if (typeof then === ‘function‘) { | |
// 调用Thenable对象的`then`方法时,传递进去的`resolvePromise`和`rejectPromise`方法(及下面的两个匿名方法) | |
// 可能会被重复调用。但Promise+规范规定这两个方法有且只能有其中的一个被调用一次,多次调用将被忽略。 | |
// 此处通过`invoked`来处理重复调用 | |
var invoked = false; | |
try { | |
then.call( | |
x, | |
function (y) { | |
if (invoked) { | |
return; | |
} | |
invoked = true; | |
// 避免死循环 | |
if (y === x) { | |
throw new TypeError(‘TypeError: The return value could not be same with the previous thenable object‘); | |
} | |
// y仍有可能是thenable对象,递归调用 | |
resolveThenable(y); | |
}, | |
function (e) { | |
if (invoked) { | |
return; | |
} | |
invoked = true; | |
reject(promise, e); | |
} | |
); | |
} | |
catch (e) { | |
// 如果`resolvePromise`和`rejectPromise`方法被调用后,再抛出异常,则忽略异常 | |
// 否则用异常对象reject此Promise对象 | |
if (!invoked) { | |
reject(promise, e); | |
} | |
} | |
} | |
else { | |
resolve(promise, x); | |
} | |
} | |
else { | |
resolve(promise, x); | |
} | |
}(x)); | |
} | |
} | |
// 如果未传递callback,直接用前一个promise传递过来的值resolve/reject当前Promise对象 | |
else { | |
action === ‘resolve‘ | |
? resolve(promise, value) | |
: reject(promise, value); | |
} | |
}; | |
} | |
return Promise; | |
}, this)); |
以上是关于promise的实现的主要内容,如果未能解决你的问题,请参考以下文章