if (typeof Promise === 'undefined') {
return
}
实现 Promise/A+ 规范的库有很多,lie 是一个精简的实现 Promise/A+ 的库,并且通过了 Promise/A+ 专门的测试集,但 lie 的代码写的有点绕,我在 lie 的代码基础上进行了修改,使之更容易阅读和理解,并发布了 appoint 模块供大家参考。
Promise/A+ 规范
Promise 规范有很多,如 Promise/A,Promise/B,Promise/D 以及 Promise/A 的升级版 Promise/A+,有兴趣的可以去了解下,最终 ES6 中采用了 Promise/A+ 规范。在讲解 Promise 实现之前,当然要先了解 Promise/A+ 规范。Promise/A+ 规范参考:
注意:没有特殊说明以下 promise 均指代 Promise 实例。
规范虽然不长,但细节也比较多,我挑出几个要点简单说明下:
- Promise 本质是一个状态机。每个 promise 只能是 3 种状态中的一种:pending、fulfilled 或 rejected。状态转变只能是 pending -> fulfilled 或者 pending -> rejected。状态转变不可逆。
- then 方法可以被同一个 promise 调用多次。
- then 方法必须返回一个 promise。规范里没有明确说明返回一个新的 promise 还是复用老的 promise(即 return this),大多数实现都是返回一个新的 promise,而且复用老的 promise 可能改变内部状态,这与规范也是相违背的。
- 值穿透。下面会细讲。
从头实现 Promise
我们知道 Promise 是一个构造函数,需要用 new 调用,并有以下几个 api:
function Promise(resolver) {}
Promise.prototype.then = function() {}
Promise.prototype.catch = function() {}
Promise.resolve = function() {}
Promise.reject = function() {}
Promise.all = function() {}
Promise.race = function() {}
下面我们以 appoint 为最终目标,开始一步一步构建完整的 Promise 实现。
'use strict';
var immediate = require('immediate');
function INTERNAL() {}
function isFunction(func) {
return typeof func === 'function';
}
function isObject(obj) {
return typeof obj === 'object';
}
function isArray(arr) {
return Object.prototype.toString.call(arr) === '[object Array]';
}
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
module.exports = Promise;
function Promise(resolver) {
if (!isFunction(resolver)) {
throw new TypeError('resolver must be a function');
}
this.state = PENDING;
this.value = void 0;
this.queue = [];
if (resolver !== INTERNAL) {
safelyResolveThen(this, resolver);
}
}
- state: 当前 promise 的状态,初始值为 PENDING。状态改变只能是 PENDING -> FULFILLED 或 PENDING -> REJECTED。
- value: 当 state 是 FULFILLED 时存储返回值,当 state 是 REJECTED 时存储错误。
- queue: promise 内部的回调队列,这是个什么玩意儿?为什么是一个数组?
Promise 实现基本原理
先看一段代码:
var Promise = require('appoint')
var promise = new Promise((resolve) => {
setTimeout(() => {
resolve('haha')
}, 1000)
})
var a = promise.then(function onSuccess() {})
var b = promise.catch(function onError() {})
console.log(require('util').inspect(promise, {
depth: 10 }))
console.log(promise.queue[0].promise === a)
console.log(promise.queue[1].promise === b)
Promise {
state: 0,
value: