Mmear's 😘.

PromiseA+ 规范实现 Promise 🚌

字数统计: 1.6k阅读时长: 7 min
2019/04/18 Share

引言

面试时曾被问到 Promise 的具体实现, 那时候只实现过一个简陋的 demo, 而且完全没体现出异步的特性, 所以没答出来 🚌; 这几天心血来潮, 参考了下面两篇文章之后, 手动实现了一个 Promise;

参考

PromiseA+ 中文规范
Promise Typescript 实现

概念

Promise

虽然在平时已经大量使用了 Promise , 但在这里还是简单介绍一下:

Promise 是异步编程的一种解决方案, 简单来说, 它就是一个对外不透明的容器, 只可能处于Pending, Fulfilled, Rejected三种状态之一, 一旦确定为后两种状态后便不能再更改, 异步回调便是在状态改变之后进行的; 如阮一峰老师文章中提到的 Promise 特点:

  • Promise 对象的状态不受外界状态影响, 外界也无法获取它的状态
  • Promise 对象的状态和结果一旦确定便不能更改, 但任何时候都能获得 Promise 对应的异步操作的执行结果
  • Promise 对象可以将异步操作用类似同步操作的流程表达出来

thenable

thenable是指一个拥有then方法的函数和对象, 对该函数或对象的解决过程即调用它的then方法; 解决过程(Resolution Procedure)PromiseA+中规定的对 Promise 对象或thenable对象的处理方法; 具体内容可以参考上文规范或下面代码中的注释;

原理

依照上面参考文章的思想, 主要采用了观察者模式结合setTimeout来模拟 Promise 异步操作的实现, 观察者模式实现的功能是 Promise 状态改变后通知 Promise 对象执行已注册的回调(比如多个then方法链式调用), setTimeout是通过往宏队列中插入任务来模拟异步回调, 实际上 Promise 的异步回调是属于浏览器事件循环中的微任务队列;

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
const States = {
PENDING: "PENDING",
RESOLVED: "RESOLVED",
REJECTED: "REJECTED"
};

// 观察者模式实现Promise的异步操作
class _Promise {
constructor(callback) {
this.state = States.PENDING;
this.value = void 0;
this.interrupt = false;
this.resolvedHandlers = [];
this.rejectedHandlers = [];
try {
callback.call(this, this._resolve.bind(this), this._reject.bind(this));
} catch (e) {
this.interrupt = true;
this._reject.call(this, e);
}
}
// resolve 或 reject 时才会改变state, 并触发then中的回调
_resolve(value) {
this._setValue(value, States.RESOLVED);
}
_reject(value) {
this._setValue(value, States.REJECTED);
}
_setValue(value, state) {
//*[规范] 状态为 Fulfilled 和 Rejected 时, 不得迁移至其它状态
if (this.state !== States.PENDING) {
return;
}
// 先不考虑 value 值为 promise / thenable 的情况
this.state = state;
//*[规范] 终值/据因必需是不可变的
this.value = value;
// 将异步回调的执行添加至宏队列中
setTimeout(this._executeHandler.bind(this), 0);
}
_executeHandler() {
if (this.state === "PENDING") {
// 状态仍未确定
return null;
}
const res =
this.state === States.RESOLVED
? this.resolvedHandlers.forEach(handler => handler())
: this.rejectedHandlers.forEach(handler => handler());
return res;
}
_isThenable(obj) {
return obj.then && typeof obj.then === "function";
}
//* 根据 x 值不同对 promise2 进行不同动作, 参见[PromiseA+规范]
_promiseCheck(x, resolve, reject, nextPromise) {
// 1. 如果 x 是 thenable 的且看上去像一个 promise, 则尝试让 promise2 接受 x 的状态
// 1.1 x === promise2
if (x && x === nextPromise)
throw new TypeError(`${x} can not be same as ${nextPromise}.`);
// 1.2 x 是一个 promise
else if (x instanceof _Promise) {
x.then(
res => nextPromise._promiseCheck(res, resolve, reject, nextPromise),
reject
).catch(reject);
}
// 1.3 x 是一个对象或函数
else if (x && (typeof x === "function" || typeof x === "object")) {
const then = x.then;
if (typeof then === "function") {
then.apply(
x,
function resolvePromise(y) {
if (y === x) throw new TypeError("Promise recursion!");
nextPromise._promiseCheck(y, resolve, reject, nextPromise);
},
function rejectPromise(r) {
reject(r);
}
);
} else {
resolve(x);
}
}
// 1.4 不符合上述情况, 使用 x 的值来执行 promise2
else resolve(x);
// 否则使用 x 的值来执行 promise2
}

//*[规范] 一个 promise 必须提供一个 then 方法以访问其当前值、终值和据因。
//*[规范] then 方法必须返回一个 promise 对象;
/**
*
* @param {Function} onFulfilled
* 当 promise 执行结束后其必须被调用
* 其第一个参数为 promise 的终值在 promise 执行结束前其不可被调用
* 其调用次数不可超过一次
* @param {Function} onRejected
* 当 promise 被拒绝执行后其必须被调用,其第一个参数为 promise 的据因
* 在 promise 被拒绝执行前其不可被调用
* 其调用次数不可超过一次
*/
//*[规范] onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用(即当前执行栈为空时调用)
//*[规范]then 方法可以被同一个 promise 调用多次
//** 当 promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调
//** 当 promise 被拒绝执行时,所有的 onRejected 需按照其注册顺序依次回调
then(onFulfilled = res => res, onRejected) {
//![规范] 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)
//![规范] 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
//![规范] 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
//![规范] 如果 onRejected 不是函数且 promise1 拒绝执行(抛出异常, 不是指promise1状态为rejected), promise2 必须拒绝执行并返回相同的据因
//~ 即:不论 promise1 被 reject 还是被 resolve 时 promise2 都会被 resolve,只有出现异常时才会被 rejected。
//* promise 状态为 pending 时, 添加至回调队列
const pendingThen = (resolve, reject, newPromise) => {
// 放入handler列表中, 等状态settle时统一处理
this.resolvedHandlers.push(() => {
try {
// 将 onFulfilled 后的值传递给新的promise
const temple = onFulfilled(this.value);
this._promiseCheck(temple, resolve, reject, newPromise);
} catch (error) {
reject(error);
}
});
this.rejectedHandlers.push(() => {
try {
typeof onRejected !== "function" && this.interrupt
? reject(this.value)
: this._promiseCheck(
onRejected(this.value),
resolve,
reject,
newPromise
);
} catch (error) {
reject(error);
}
});
};
//* promise 状态为 fulfilled 时
const resolvedThen = (resolve, reject) => {
// 状态已经 settle, 直接返回 fulfilled 后的值
// then不会堵塞主进程, 放到异步队列中执行
setTimeout(() => {
try {
const temple = onFulfilled(this.value);
this._promiseCheck(temple, resolve, reject, newPromise);
} catch (error) {
reject(error);
}
}, 0);
};
//* promise 状态为 rejected 时
const rejectedThen = (resolve, reject) => {
setTimeout(() => {
try {
typeof onRejected !== "function" && this.interrupt
? reject(this.value)
: this._promiseCheck(
onRejected(this.value),
resolve,
reject,
newPromise
);
} catch (error) {
reject(error);
}
}, 0);
};
let nextPromise;
nextPromise = new _Promise((resolve, reject) => {
// 如果当前 Promise 状态还为 PENDING
switch (this.state) {
case States.PENDING:
pendingThen(resolve, reject, nextPromise);
break;
case States.RESOLVED:
resolvedThen(resolve, reject, nextPromise);
break;
case States.REJECTED:
rejectedThen(resolve, reject, nextPromise);
}
});
return nextPromise;
}
}
CATALOG
  1. 1. 引言
  2. 2. 参考
  3. 3. 概念
    1. 3.1. Promise
    2. 3.2. thenable
  4. 4. 原理
  5. 5. 代码