promise 实现

规范 | 中文解析

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
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.callbacks = [];
let resolve = (val) => {
this._execCallback(FULFILLED, val);
};
let reject = (reason) => {
this._execCallback(REJECTED, reason);
};
try {
fn(resolve, reject);
} catch (err) {
this._reject(err);
}
}
_execCallback(status, val) {
if (this.status !== PENDING) {
return;
}
this.status = status;
this.value = val;
this.callbacks.forEach((cb) => cb());
}
//规范 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((y) => {
this._resolvePromise(newPromise, y, resolve, reject);
}, reject);
//规范 2.3.3
} else if (isObj(x) || isFunc(x)) {
if (x === null) {
return resolve(x);
}
let then = undefined;
try {
//规范 2.3.3.1 把 x.then 赋值给 then
then = x.then;
} catch (err) {
//规范 2.3.3.2
return reject(err);
}
//规范 2.3.3.3
if (isFunc(then)) {
let called = false;
try {
then.call(
x,
(y) => {
if (called) return;
called = true;
this._resolvePromise(newPromise, y, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} catch (err) {
if (called) return;
reject(err);
}
} else {
//规范 2.3.3.4
resolve(x);
}
} else {
//规范 2.3.4
resolve(x);
}
}
//规范 2.2 promise.then(onFulfilled, onRejected)
then(onFulfilled, onRejected) {
//规范 2.2.1.1,2.2.7.3
onFulfilled = isFunc(onFulfilled) ? onFulfilled : (val) => val;
// //规范 2.2.1.2,2.2.7.4
onRejected = isFunc(onRejected)
? onRejected
: (err) => {
throw err;
};
const promise2 = new MyPromise((resolve, reject) => {
const fn = () => {
//规范 2.2.4, 2.2.5 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用,且被作为函数调用(即没有 this 值)
setTimeout(() => {
try {
const x = this.status === FULFILLED ? onFulfilled(this.value) : onRejected(this.value);
//规范 2.2.7.1
this._resolvePromise(promise2, x, resolve, reject);
} catch (err) {
//规范 2.2.7.2
reject(err);
}
});
};
// 规范 2.2.6
this.status === PENDING ? this.callbacks.push(fn) : fn();
});
// 规范 2.2.7
return promise2;
}
//catch 方法
catch(onRejected) {
return this.then(null, onRejected);
}
//finally 方法
finally(cb) {
return this.then(
(val) => {
return MyPromise.resolve(cb()).then(() => val);
},
(err) => {
return 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) {
return new MyPromise((resolve, reject) => {
let count = 0;
let valueList = [];
const promises = Array.from(params);
if (promises.length === 0) {
return resolve(valueList);
}
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) {
return new MyPromise((resolve, reject) => {
const promises = Array.from(params);
if (promises.length === 0) {
return resolve();
}
promises.forEach((item) => {
if (!item instanceof MyPromise) {
item = MyPromise.resolve(item);
}
item.then(resolve, reject);
});
});
}
//用于 promise test
static deferred() {
const result = {};
result.promise = new MyPromise((resolve, reject) => {
result.resolve = resolve;
result.reject = reject;
});
return result;
}
}

module.exports = MyPromise;

promise 测试

手写的 Promise 可通过promises-aplus-tests测试是否符合规范,Promise 内部添加 deferred 静态方法并导出:

1
2
3
4
5
6
7
8
9
static deferred() {
const result = {};
result.promise = new MyPromise((resolve, reject) => {
result.resolve = resolve;
result.reject = reject;
});
return result;
}
module.exports = MyPromise;

然后执行命令:

1
promises-aplus-tests MyPromise

测试结果

chrome 里的实现

实践中要确保 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 开发实现。