本文遵循的Promise/A+
标准实现一个简略版本Promise, 用代码了解标准中的每一句话.
Promise/A+
英文版标准, 中文版标准;- es6中Promise残缺标准
- 浏览器中Promise实现
Promise 的状态
标准形容
一个 Promise 的以后状态必须为以下三种状态中的一种:期待态(Pending)、实现态(Fulfilled)和回绝态(Rejected)。
期待态(Pending)
处于期待态时,promise 需满足以下条件:- 能够迁徙至执行态或回绝态
实现态(Fulfilled)
处于执行态时,promise 需满足以下条件:- 不能迁徙至其余任何状态
- 必须领有一个不可变的终值
回绝态(Rejected)
处于回绝态时,promise 需满足以下条件:- 不能迁徙至其余任何状态
- 必须领有一个不可变的据因
代码实现
采纳类实现:
class MyPromise {}
实现构造函数:
const _ = require('lodash');const PENDING = 0;const FULFILLED = 1;const REJECTED = 2;class MyPromise { constructor(executor) { if (!(this instanceof MyPromise)) { throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); } if (!_.isFunction(executor)) { throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); } this._status = PENDING; this._value = undefined; this._thenCallbacks = []; this._reason = undefined; try { executor((...args) => this._resolve(...args), (...args) => this._reject(...args)); } catch(e) { this._reject(e); } }}
在构造函数中, 首先处理函数边界, 而后初始化状态,终值(_value), 拒因(_reason)和then
的回调函数队列; 最初调用传入的executor
.executor
中用于管制Promise
状态的变动.传递两个回调函数作为参数,第一个参数叫做resove
,第二个参数叫做 reject
, 在对象中的解决解决逻辑为:
_resolve(value) { if (this._status !== PENDING) { return; } this._status = FULFILLED; this._value = value; } _reject(reason) { if (this._status !== PENDING) { return; } this._status = REJECTED; this._reason = reason; }
_resolve
, _reject
有状态边界判断, 如果被调用屡次, 采纳首次调用并疏忽剩下的调用._resolve
中只容许期待态转为实现态,而后接管终值._reject
中只容许期待态转为回绝态, 而后接管拒因.
状态的判断保障_resolve
,_reject
中次要逻辑在以后promise
中最多被执行一次: 状态最多扭转一次;then
的回调函数最多调用一次.
Then函数
标准形容
一个promise
必须提供一个then
办法以拜访其以后值、终值和据因。promise
的then
办法承受两个参数:
promise.then(onFulfilled, onRejected)
参数可选
onFulfilled
和onRejected
都是可选参数。
- 如果
onFulfilled
不是函数,其必须被疏忽 - 如果
onRejected
不是函数,其必须被疏忽
onFulfilled
个性
如果onFulfilled
是函数:
- 当
promise
执行完结后其必须被调用,其第一个参数为promise
的终值 - 在
promise
执行完结前其不可被调用 - 其调用次数不可超过一次
调用机会
onFulfilled
和onRejected
只有在执行环境堆栈仅蕴含平台代码时才可被调用
调用要求
onFulfilled
和onRejected
必须被作为函数调用(即没有 this 值)注2
屡次调用
then
办法能够被同一个promise
调用屡次
当promise
胜利执行时,所有onFulfilled
需依照其注册程序顺次回调
当promise
被拒绝执行时,所有的onRejected
需依照其注册程序顺次回调
返回
then
办法必须返回一个promise
对象
promise2 = promise1.then(onFulfilled, onRejected);
- 如果
onFulfilled
或者onRejected
返回一个值 x ,则运行上面的Promise
解决过程:[[Resolve]](promise2, x)
- 如果
onFulfilled
或者onRejected
抛出一个异样e
,则promise2
必须拒绝执行,并返回拒因e
- 如果
onFulfilled
不是函数且promise1
胜利执行,promise2
必须胜利执行并返回雷同的值 - 如果 onRejected 不是函数且
promise1
拒绝执行,promise2
必须拒绝执行并返回雷同的据因
代码实现
须要在构造函数增加回调函数队列:
constructor(executor) { // ... this._value = undefined; this._thenCallbacks = []; this._reason = undefined; // ... }
首先, 实现一个then
函数.因为本章节代码牵扯到很多局部, 所以尽量用代码正文来阐明实现的标准:
then(onFulfilled, onRejected) { // 如果 onFulfilled 不是函数,其必须被疏忽 const _onFulfilled = _.isFunction(onFulfilled) ? onFulfilled : void 0; // 如果 onRejected 不是函数,其必须被疏忽 const _onRejected = _.isFunction(onRejected) ? onRejected : void 0; // then 办法能够被同一个 promise 调用屡次 this._thenCallbacks.push([_onFulfilled, _onRejected]); return new MyPromise((resolve, reject) => { // 期待实现 }); }
onFulfilled
和onRejected
, 须要在_resove
或者reject
时被调用, 将resolve
, reject
革新为:
_resolve(value) { if (this._status !== PENDING) { return; } this._status = FULFILLED; this._value = value; // 如果then的回调函数onFulfilled, onRejected为函数的话, 须要 // 在 promise 执行完结前其不可被调用,当 promise 执行完结后其必须被调用 // 其调用次数不可超过一次 // 只有在执行环境堆栈仅蕴含平台代码时才可被调用 process.nextTick(this._callThenCallbacks); } _reject(reason) { if (this._status !== PENDING) { return; } this._status = REJECTED; this._reason = reason; // 如果then的回调函数onFulfilled, onRejected为函数的话, 须要 // 在 promise 执行完结前其不可被调用,当 promise 执行完结后其必须被调用 // 其调用次数不可超过一次 // 只有在执行环境堆栈仅蕴含平台代码时才可被调用 process.nextTick(this._callThenCallbacks); }
尽管标准中没有阐明onFulfilled
和onRejected
必须为微工作(micro-task)还是宏工作(macro-task),然而其余实现根本都是基于微工作.
这里因为本文只是在node环境实现,所以采纳process.nextTick
来启用微工作, 为了跨平台, 个别的Promise实现框架, 都会应用多种形式来实现在执行环境堆栈仅蕴含平台代码时才可被调用, 如MutationObserver
, MessageChannel
, vertx
等, 最初可能应用setTimeout
实现.
依照Promise/A+
标准来说,onFulfilled
和onRejected
只有在执行环境堆栈仅蕴含平台代码时才可被调用, 然而在nodejs
或者es6环境中的Promise
对象, 须要像上面的实现:
_resolve(value) { // 只有在执行环境堆栈仅蕴含平台代码时才可被调用 process.nextTick(() => { if (this._status !== PENDING) { return; } this._status = FULFILLED; this._value = value; // 如果then的回调函数onFulfilled, onRejected为函数的话, 须要 // 在 promise 执行完结前其不可被调用,当 promise 执行完结后其必须被调用 // 其调用次数不可超过一次 // 只有在执行环境堆栈仅蕴含平台代码时才可被调用 // process.nextTick(() => this._callThenCallbacks()); this._callThenCallbacks(); }); } _reject(reason) { // 只有在执行环境堆栈仅蕴含平台代码时才可被调用 process.nextTick(() => { if (this._status !== PENDING) { return; } this._status = REJECTED; this._reason = reason; // 如果then的回调函数onFulfilled, onRejected为函数的话, 须要 // 在 promise 执行完结前其不可被调用,当 promise 执行完结后其必须被调用 // 其调用次数不可超过一次 // process.nextTick(() => this._callThenCallbacks()); this._callThenCallbacks(); }); }
对于比拟风行的prmise polyfill库es-promise
的实现,采纳的是下面一种启用微工作的机会, 对于babel中的垫片core-js中实现的promise
, 采纳的是下一种启用机会.
Then函数.返回标准有简单的要求,为了实现这些要求, 须要扭转下面的then
函数的实现:
then(onFulfilled, onRejected) { // 如果 onFulfilled 不是函数,其必须被疏忽 const _onFulfilled = _.isFunction(onFulfilled) ? onFulfilled : void 0; // 如果 onRejected 不是函数,其必须被疏忽 const _onRejected = _.isFunction(onRejected) ? onRejected : void 0; let childResolve; let childReject; const childPromise = new MyPromise((resolve, reject) => { childResolve = resolve; childReject = reject; }); // then 办法能够被同一个 promise 调用屡次 this._thenCallbacks.push([_onFulfilled, _onRejected, childResolve, childReject]); return childPromise; }
_callThenCallbacks
用于解决在promise
状态扭转后处理then
回调函数队列. 在解决每一个then
回调函数后, 还须要对于then
回调函数返回的后果, 联合以后的promise
状态,调整以后then
函数返回的promise2
的状态:
// 调用then回调函数队列 _callThenCallbacks() { if (_.isEmpty(this._thenCallbacks)) { return; } this._thenCallbacks.forEach(([onFulfilled, onRejected, childResolve, childReject]) => { try { if (this._status === FULFILLED && !onFulfilled) { // 如果 onFulfilled 不是函数且 promise1 胜利执行, promise2 必须胜利执行并返回雷同的值 childResolve(this._value); return; } if (this._status === REJECTED && !onRejected) { // 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回雷同的据因 childReject(this._reason); } let x; if (this._status === REJECTED && onRejected) { // 当 promise 被拒绝执行时,所有的 onRejected 需依照其注册程序顺次回调 // 其第一个参数为 promise 的拒因 // 必须被作为函数调用(即没有 this 值) x = onRejected(this._reason); } else if (this._status === FULFILLED && onFulfilled) { // 当 promise 胜利执行时,所有 onFulfilled 需依照其注册程序顺次回调 // 其第一个参数为 promise 的终值 // 必须被作为函数调用(即没有 this 值) x = onFulfilled(this._value); } // 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行上面的 Promise 解决过程 this._resolvePromise(x, childResolve, childReject); } catch (error) { childReject(error); } }); }
其中_resolvePromise
代表Promise解决过程, 将在下文阐明.
Promise解决过程
标准形容
Promise解决过程是一个形象的操作,其需输出一个promise
和一个值,咱们示意为[[Resolve]](promise, x)
,如果x
有then
办法且看上去像一个Promise,解决程序即尝试使promise
承受x
的状态;否则其用x
的值来执行 promise 。
这种thenable
的个性使得Promise
的实现更具备通用性:只有其暴露出一个遵循 Promise/A+ 协定的then
办法即可;这同时也使遵循 Promise/A+ 标准的实现能够与那些不太标准但可用的实现能良好共存。
运行[[Resolve]](promise, x)
需遵循以下步骤:
x
与promise
相等
如果x
为Promise,则使promise 承受
x`的状态:- 如果
x
处于期待态,promise
需放弃为期待态直至x
被执行或回绝 - 如果
x
处于执行态,用雷同的值执行promise
- 如果
x
处于回绝态,用雷同的据因回绝promise
- 如果
x
为对象或函数
如果x
为对象或者函数:- 把
x.then
赋值给then
- 如果取
x.then
的值时抛出谬误e
,则以e
为据因回绝promise
如果
then
是函数,将x
作为函数的作用域this
调用之。传递两个回调函数作为参数,第一个参数叫做resolvePromise
,第二个参数叫做rejectPromise
:- 如果
resolvePromise
以值y
为参数被调用,则运行[[Resolve]](promise, y)
- 如果
rejectPromise
以据因r
为参数被调用,则以据因r
回绝promise
- 如果
resolvePromise
和rejectPromise
均被调用,或者被同一参数调用了屡次,则优先采纳首次调用并疏忽剩下的调用 如果调用
then
办法抛出了异样e
:- 如果
resolvePromise
或rejectPromise
曾经被调用,则疏忽之 - 否则以
e
为据因回绝promise
- 如果
- 如果
then
不是函数,以x
为参数执行promise
- 如果
- 把
- 如果
x
不为对象或者函数,以x为参数执行
promise`
如果一个promise
被一个循环的thenable
链中的对象解决,而[[Resolve]](promise, thenable)
的递归性质又使得其被再次调用,根据上述的算法将会陷入有限递归之中。算法虽不强制要求,但也激励施者检测这样的递归是否存在,若检测到存在则以一个可辨认的TypeError
为据因来回绝promise
.
代码实现
函数_resolvePromise
实现, 采纳代码正文阐明:
// Promise 解决过程 _resolvePromise(x, childResolve, childReject) { // x 与 promise 相等 if (x === this) { // 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise throw new TypeError("You cannot resolve a promise with itself"); } // 如果 x 为 Promise ,则使 promise 承受 x 的状态 if (x instanceof MyPromise) { // 如果 x 处于期待态 console.log('======PENDING===', x._status); if (x._status === PENDING) { // promise 需放弃为期待态直至 x 被执行或回绝 x.then(childResolve, childReject); return; } // 如果 x 处于执行态 if (x._status === FULFILLED) { // 用雷同的值执行 promise childResolve(x._value); return; } // 如果 x 处于执行态 if (x._status === REJECTED) { // 用雷同的值执行 promise childReject(x._reason); return; } } // x 为对象或函数 if (_.isObject(x) || _.isFunction(x)) { // 把 x.then 赋值给 then let then; try { then = x.then; } catch (error) { // 如果取 x.then 的值时抛出谬误 e ,则以 e 为据因回绝 promise // 其实这里不须要捕捉, 因为最外层有捕捉, 这里为了放弃跟标准统一 childReject(error); return; } // 如果 then 是函数 if (_.isFunction(then)) { // 将 x 作为函数的作用域 this 调用之 let called = false; try { then.call(x, (y) => { // 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了屡次, // 则优先采纳首次调用并疏忽剩下的调用 if (called) { return; } called = true; // 如果 resolvePromise 以值 y 为参数被调用 this._resolvePromise(y, childResolve, childReject); }, (r) => { // 如果 resolvePromise 或 rejectPromise 曾经被调用,则疏忽之 if (called) { return; } called = true; // 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 回绝 promise childReject(r); }); } catch (error) { // 如果调用 then 办法抛出了异样 e // 如果 resolvePromise 或 rejectPromise 曾经被调用,则疏忽之 if (called) { return; } // 否则以 e 为据因回绝 promise childReject(error); } return; } // 如果 then 不是函数, 以 x 为参数执行 promise childResolve(x); return; } // 如果 x 不为对象或者函数, 以 x 为参数执行 promise childResolve(x); }
全副代码
const _ = require('lodash');const PENDING = 0;const FULFILLED = 1;const REJECTED = 2;class MyPromise { constructor(executor) { if (!(this instanceof MyPromise)) { throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); } if (!_.isFunction(executor)) { throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); } this._status = PENDING; this._value = undefined; this._thenCallbacks = []; this._reason = undefined; try { executor((...args) => this._resolve(...args), (...args) => this._reject(...args)); } catch(e) { this._reject(e); } } _resolve(value) { // 只有在执行环境堆栈仅蕴含平台代码时才可被调用 process.nextTick(() => { if (this._status !== PENDING) { return; } this._status = FULFILLED; this._value = value; // 如果then的回调函数onFulfilled, onRejected为函数的话, 须要 // 在 promise 执行完结前其不可被调用,当 promise 执行完结后其必须被调用 // 其调用次数不可超过一次 // 只有在执行环境堆栈仅蕴含平台代码时才可被调用 // process.nextTick(() => this._callThenCallbacks()); this._callThenCallbacks(); }); } _reject(reason) { // 只有在执行环境堆栈仅蕴含平台代码时才可被调用 process.nextTick(() => { if (this._status !== PENDING) { return; } this._status = REJECTED; this._reason = reason; // 如果then的回调函数onFulfilled, onRejected为函数的话, 须要 // 在 promise 执行完结前其不可被调用,当 promise 执行完结后其必须被调用 // 其调用次数不可超过一次 // 只有在执行环境堆栈仅蕴含平台代码时才可被调用 // process.nextTick(() => this._callThenCallbacks()); this._callThenCallbacks(); }); } // 调用then回调函数队列 _callThenCallbacks() { if (_.isEmpty(this._thenCallbacks)) { return; } this._thenCallbacks.forEach(([onFulfilled, onRejected, childResolve, childReject]) => { try { if (this._status === FULFILLED && !onFulfilled) { // 如果 onFulfilled 不是函数且 promise1 胜利执行, promise2 必须胜利执行并返回雷同的值 childResolve(this._value); return; } if (this._status === REJECTED && !onRejected) { // 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回雷同的据因 childReject(this._reason); } let x; if (this._status === REJECTED && onRejected) { // 当 promise 被拒绝执行时,所有的 onRejected 需依照其注册程序顺次回调 // 其第一个参数为 promise 的拒因 // 必须被作为函数调用(即没有 this 值) x = onRejected(this._reason); } else if (this._status === FULFILLED && onFulfilled) { // 当 promise 胜利执行时,所有 onFulfilled 需依照其注册程序顺次回调 // 其第一个参数为 promise 的终值 // 必须被作为函数调用(即没有 this 值) x = onFulfilled(this._value); } // 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行上面的 Promise 解决过程 this._resolvePromise(x, childResolve, childReject); } catch (error) { childReject(error); } }); } // Promise 解决过程 _resolvePromise(x, childResolve, childReject) { // x 与 promise 相等 if (x === this) { // 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise throw new TypeError("You cannot resolve a promise with itself"); } // 如果 x 为 Promise ,则使 promise 承受 x 的状态 if (x instanceof MyPromise) { // 如果 x 处于期待态 console.log('======PENDING===', x._status); if (x._status === PENDING) { // promise 需放弃为期待态直至 x 被执行或回绝 x.then(childResolve, childReject); return; } // 如果 x 处于执行态 if (x._status === FULFILLED) { // 用雷同的值执行 promise childResolve(x._value); return; } // 如果 x 处于执行态 if (x._status === REJECTED) { // 用雷同的值执行 promise childReject(x._reason); return; } } // x 为对象或函数 if (_.isObject(x) || _.isFunction(x)) { // 把 x.then 赋值给 then let then; try { then = x.then; } catch (error) { // 如果取 x.then 的值时抛出谬误 e ,则以 e 为据因回绝 promise // 其实这里不须要捕捉, 因为最外层有捕捉, 这里为了放弃跟标准统一 childReject(error); return; } // 如果 then 是函数 if (_.isFunction(then)) { // 将 x 作为函数的作用域 this 调用之 let called = false; try { then.call(x, (y) => { // 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了屡次, // 则优先采纳首次调用并疏忽剩下的调用 if (called) { return; } called = true; // 如果 resolvePromise 以值 y 为参数被调用 this._resolvePromise(y, childResolve, childReject); }, (r) => { // 如果 resolvePromise 或 rejectPromise 曾经被调用,则疏忽之 if (called) { return; } called = true; // 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 回绝 promise childReject(r); }); } catch (error) { // 如果调用 then 办法抛出了异样 e // 如果 resolvePromise 或 rejectPromise 曾经被调用,则疏忽之 if (called) { return; } // 否则以 e 为据因回绝 promise childReject(error); } return; } // 如果 then 不是函数, 以 x 为参数执行 promise childResolve(x); return; } // 如果 x 不为对象或者函数, 以 x 为参数执行 promise childResolve(x); } then(onFulfilled, onRejected) { // 如果 onFulfilled 不是函数,其必须被疏忽 const _onFulfilled = _.isFunction(onFulfilled) ? onFulfilled : void 0; // 如果 onRejected 不是函数,其必须被疏忽 const _onRejected = _.isFunction(onRejected) ? onRejected : void 0; let childResolve; let childReject; const childPromise = new MyPromise((resolve, reject) => { childResolve = resolve; childReject = reject; }); // then 办法能够被同一个 promise 调用屡次 this._thenCallbacks.push([_onFulfilled, _onRejected, childResolve, childReject]); return childPromise; }}module.exports = MyPromise;