200 行逐行分解 Promise 模拟实现(ES6)

再看不懂你就来砍我吧

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
198
199
200
201
// 如何快速写一个 Promise
var MyPromise = (function() {
// 1. 三种状态
var PENDING = 'pending';
var FULFILLED = 'fulfilled';
var REJECTED = 'rejected';
/**
* 2. `Promise constructor` 是一个函数,通过 `new` 操作符调用,接受一个立即执行的函数作为参数
* @param {function} executor
* @returns Promise
*/
function _Promise(executor){
var p = this
// 3. 初始化状态,成功,失败异步队列
p.status = PENDING
p.value = null
p.reason = null
p.onFulfilled = []
p.onRejected = []
try {
// 4. 立即执行这个函数,并给这个函数传入两个入参(resolve, reject)用于改变 promise 状态
executor(function(value){
// 5. resolvePromise 通过此方法接着解决 promise
resolvePromise(p, value)
}, function(reason){
rejectPromise(p, reason)
})
} catch (error) {
rejectPromise(p, error)
}
// 返回一个 Promise 实例
return p
}
/**
* 6. then 方法接受两个回调方法,并返回一个新的 promise 对象
* @param {function} onFulfilled 成功回调
* @param {function} onRejected 失败回调
* @returns promise
*/
_Promise.prototype.then = function(onFulfilled, onRejected){
// 7. 需要对回调方法进行兼容
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value){ return value }
onRejected = typeof onRejected === 'function' ? onRejected : function(reason){ throw reason }
// 8. 当前的 `promise` 实例
var p1 = this
// 9. 返回一个新的 `promise` 实例
var p2 = new MyPromise(function(){})
// 10. 注册微任务事件
function fulfilled(){
// 注册一个微任务
queueMicrotask(function(){
try {
var x = onFulfilled(p1.value)
// 这里得注意要使用 p2
resolvePromise(p2, x)
} catch (error) {
rejectPromise(p2, error)
}
})
}
function rejected(){
queueMicrotask(function(){
try {
var x = onRejected(p1.reason)
resolvePromise(p2, x)
} catch (error) {
rejectPromise(p2, error)
}
})
}
// 判断状态
var status = p1.status
if(status === PENDING){
// 推入队列中
p1.onFulfilled.push(fulfilled)
p1.onRejected.push(rejected)
}else if(status === FULFILLED){
// 立即执行
fulfilled()
}else if(status === REJECTED){
// 立即执行
rejected()
}
// 返回一个新的 promise 实例
return p2
}
/**
* 15. 补一个 runCb 方法执行回调函数
* @param {function[]} cbs
* @param {any} val
*/
function runCbs(cbs, val){
cbs.forEach(function(cb){
cb(val)
})
}
// 11. 接着来写三个处理promise状态的函数
/**
* 16. 失败的 promise 处理方法
* @param {promise} p promise 实例
* @param {any} reason 失败原因
* @returns
*/
function rejectPromise(p, reason){
// 12. rejected 的时候得这么做呢?首先判断当前状态是否为 PENDING
if(p.status !== PENDING) return
// 13. 更改状态,保存 reason
p.status = REJECTED
p.reason = reason
// 14. 依次执行 onRejected 中的回调方法
runCbs(p.onRejected, p.reason)
}
/**
* 17. 成功的 promise 处理方法
* @param {promise} p promise 实例
* @param {any} value
*/
function fulfillPromise(p, value){
// 18. 同样的,判断状态,更改状态,保存值,执行函数
if(p.status !== PENDING) return
p.status = FULFILLED
p.value = value
runCbs(p.onFulfilled, p.value)
}
/**
* promise resolve 程序,核心
* @param {promise} p 需要被解决的 promise 实例
* @param {any} x
*/
function resolvePromise(p, x){
// 19. 禁止递归调用
if(p === x) return rejectPromise(p, new TypeError('same'))
// 20. 如果 x 是一个 promise 实例的情况
if(x instanceof MyPromise){
// 21. 如果 x 还是一个等待中的状态,往 then 增加回调处理
if(x.status === PENDING){
x.then(function(value){
resolvePromise(p, value)
}, function(reason){
rejectPromise(p, reason)
})
}else if(x.status === FULFILLED){
// 22. 如果是一个已成功的状态,直接使用成功的处理方法
fulfillPromise(p, x.value)
}else if(x.status === REJECTED){
// 23. 如果是一个已失败的状态,直接使用失败的处理方法
rejectPromise(p, x.reason)
}
}else if(x && (typeof x === 'function' || typeof x === 'object')){
// 25. 这里是处理 thenable 的情况
var then
try {
then = x.then
} catch (error) {
// 26. 报错则直接失败
rejectPromise(p, error)
}
if(typeof then === 'function'){
// 这里需要只调用一次
var done = false
try {
// 调用 then
then.call(x, function(y){
if(done) return
done = true
// 接着解决
resolvePromise(p, y)
}, function(reason){
if(done) return
done = true
rejectPromise(p, reason)
})
} catch (error) {
if(done) return
done = true
rejectPromise(p, error)
}
}else{
// 27. 如果不是一个函数,则直接成功
fulfillPromise(p, x)
}
}else{
// 24. 其他情况都算成功
fulfillPromise(p, x)
}
}
return _Promise
})();

// npm i --save promises-aplus-tests && promises-aplus-tests index.js
// 就可以测试是否符合 Promise A+ 规范
MyPromise.deferred = function(){
var result = {}
result.promise = new MyPromise(function(resolve, reject){
result.resolve = resolve
result.reject = reject
})
return result
}

module.exports = MyPromise

image.png

关于 then 方法的规范

image.png

流转图

image.png

再贴一个 ES6 的实现

code.png

源码地址