promise 实现

规范 | 中文解析

相关术语及概念见上述链接,以下为 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
188
189
190
191
192
193
194
195
196
197
const isFunc = (obj) => Object.prototype.toString.call(obj) === '[object Function]';
const isObj = (obj) => Object.prototype.toString.call(obj) === '[object Object]';
// 等待态 规范 2.1.1
const PENDING = 'pending';
// 执行态 规范 2.1.2
const FULFILLED = 'fulfilled';
// 拒绝态 规范 2.1.3
const REJECTED = 'rejected';

class MyPromise {
constructor(fn) {
this.status = PENDING;
this.value = undefined;
this.filfulledQueues = [];
this.rejectedQueues = [];
try {
fn(this._resolve.bind(this), this._reject.bind(this));
} catch (err) {
this._reject(err);
}
}
//传入 promise 的第一个参数 resolve
_resolve(val) {
if (val instanceof MyPromise) {
val.then(this._resolve, this._reject);
} else if (isObj(val) || isFunc(val)) {
try {
if (isFunc(val.then)) {
val.then(this._resolve, this._reject);
}
} catch (e) {
this._reject(e);
}
}
this._execCallback(FULFILLED, this.filfulledQueues, val);
}
//传入 promise 的第二个参数 reject
_reject(val) {
this._execCallback(REJECTED, this.rejectedQueues, val);
}
_execCallback(status, list, val) {
//规范 2.2.4 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用,且被作为函数调用(即没有 this 值)
setTimeout(() => {
if (this.status !== PENDING) {
return;
}
this.status = status;
this.value = val;
let cb;
//规范 2.2.6
while ((cb = list.shift())) {
cb(val);
}
});
}
//规范 2.3 Promise 解决过程 [[Resolve]](promise, x)
_resolvePromise(newPromise, x, resolve, reject) {
if (newPromise === x) {
//规范 2.3.1
return reject(new TypeError('循环引用'));
}
if (x instanceof MyPromise) {
//规范 2.3.2
x.then(resolve, reject);
} else if (isObj(x) || isFunc(x)) {
//规范 2.3.3
try {
//规范 2.3.3.3
if (isFunc(x.then)) {
x.then(resolve, reject);
} else {
//规范 2.3.3.4
resolve(x);
}
} catch (e) {
//规范 2.3.3.3.4
reject(e);
}
} else {
//规范 2.3.4
resolve(x);
}
}
//规范 2.2
then(onFulfilled, onRejected) {
let newPromise;
//规范 2.2.1,2.2.7.3
onFulfilled = isFunc(onFulfilled) ? onFulfilled : (val) => val;
//规范 2.2.1,2.2.7.4
onRejected = isFunc(onRejected)
? onRejected
: (err) => {
throw err;
};
//规范 2.2.7 then 方法必须返回一个 promise 对象:promise2 = promise1.then(onFulfilled, onRejected);
return (newPromise = new MyPromise((onFulfilledNext, onRejectedNext) => {
// onFulfilledNext, onRejectedNext 即该 then 的下一个 then 里传的 resolve 和 reject
if (this.status === FULFILLED || this.status === REJECTED) {
//规范 2.2.4 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用
setTimeout(() => {
// 规范 2.2.7.1 不论 promise1 被 reject 还是被 resolve 时 promise2 都会被 resolve(走_resolvePromise方法),只有出现异常时才会被 rejected。
try {
//规范 2.2.2,2.2.3,2.2.5
const x = this.status === FULFILLED ? onFulfilled(this.value) : onRejected(this.value);
this._resolvePromise(newPromise, x, onFulfilledNext, onRejectedNext);
} catch (e) {
//规范 2.2.7.2 这里如果x为捕获的err(即 onRejected 不是函数 2.2.7.4)也会进入
onRejectedNext(e);
}
});
} else if (this.status === PENDING) {
//规范 2.2.6.1
this.filfulledQueues.push(() => {
try {
//规范 2.2.2,2.2.5
const x = onFulfilled(this.value);
this._resolvePromise(newPromise, x, onFulfilledNext, onRejectedNext);
} catch (e) {
//规范 2.2.7.2
onRejectedNext(e);
}
});
//规范 2.2.6.2
this.rejectedQueues.push(() => {
try {
//规范 2.2.3,2.2.5
const x = onRejected(this.value);
this._resolvePromise(newPromise, x, onFulfilledNext, onRejectedNext);
} catch (e) {
//规范 2.2.7.2
onRejectedNext(e);
}
});
}
}));
}
//catch 方法
catch(onRejected) {
return this.then(null, onRejected);
}
//finally 方法
finally(cb) {
return this.then(
(val) => {
MyPromise.resolve(cb()).then(() => val);
},
(err) => {
MyPromise.resolve(cb()).then(() => {
throw err;
});
}
);
}
//resolve 方法
static resolve(params) {
return new MyPromise((resolve) => {
resolve(params);
});
}
//reject 方法
static reject(err) {
return new MyPromise((resolve, reject) => {
reject(err);
});
}
//all 方法
static all(params) {
let count = 0;
let valueList = [];
const promises = Array.from(params);
return new MyPromise((resolve, reject) => {
promises.forEach((item, index) => {
if (!item instanceof MyPromise) {
item = MyPromise.resolve(item);
}
item.then((r) => {
valueList[index] = r;
if (promises.length === ++count) {
resolve(valueList);
}
}, reject);
});
});
}
//race 方法
static race(params) {
const promises = Array.from(params);
return new MyPromise((resolve, reject) => {
promises.forEach((item) => {
if (!item instanceof MyPromise) {
item = MyPromise.resolve(item);
}
item.then(resolve, reject);
});
});
}
}

注:实践中要确保 onFulfilledonRejected 方法异步执行,且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。 本实现代码采用 setTimeout(宏任务)来实现异步任务,而 chrome 里的 promise 实现则是采用微任务(%EnqueueMicrotask)的方式,故略有不同。

chromepromise 实现参考源码版本小于 5.6.100src/js/promise.js 文件,其中 PromiseEnqueue 方法里的 C 函数 %EnqueueMicrotaskPromiseHandle 加入到 JS运行时 的微任务队列中。

其中因为 chrome 版本的不断迭代, 在版本 5.6.100 里的 hash6f94a8 的提交里重写了整个 PromiseEnqueue,然后在后续版本 6.1.395 里的 hashbba473 的提交里完全删除了 promise.js),最终由 JS 实现完全迭代为 C 开发实现。

---- 本文结束,感谢您的阅读 ----