# mini-Promise
- 了解Promise的内部执行机制
- 尝试封装一个mini版Promise
# 原生Promise使用
看出来了这里需要接收一个函数,像这样:
- Promise是一个构造函数,原型上绑定三个静态属性分别为then、catch、finally这几个静态方法
- 构造函数实例也有这几个钩子函数
# 开始封装
- 这里主要解释下代码执行机制
- 注释部分解释
// @ts-nocheck
class Promise2 {
//默认是pending状态
state = "pending"
//缓存因为异步执行函数
/**
* 像这样 new Promise((resolve,reject) => {
* setTimeout()
* resolve()
* })
*
*/
callbacks = []
private resolveOrReject(state, data, i) {
// 初始状态state是pending
if (this.state !== "pending") return
this.state = state
//nextTick 是我手写的异步调用栈,会在浏览器主线程执行完毕后触发
//你可以理解Promise.then触发后 最后会走到这里,并且它总会在最后执行
nextTick(() => {
this.callbacks.forEach(handle => {
if (typeof handle[i] === "function") {
let x
try {
x = handle[i].call(undefined, data)
} catch (e) {
return handle[2].reject(e)
}
handle[2].resolveWith(x)
}
})
})
}
/**
* 核心方法执行 resolveOrReject这个方法
*/
private resolve(result) {
this.resolveOrReject("fulfilled", result, 0)
}
private reject(reason) {
this.resolveOrReject("rejected", reason, 1)
}
constructor(fn) {
if (typeof fn !== "function") {
//构造函数默认必须接收一个函数、否则报错
throw new Error("The argument must be a function type!");
}
//执行传入的函数
/**
* new Promise((resolve, reject) => {})
* this.resolve.bind(this) ===> resolve
* this.reject.bind(this) ===> reject
*/
fn(this.resolve.bind(this), this.reject.bind(this))
}
// then接收两个非必填函数参数、并缓存到一个临时数组中
//最终为返回一个新的Promise实例
then(succeed?, fail?) {
const handle = []
if (typeof succeed === "function") {
handle[0] = succeed
}
if (typeof fail === "function") {
handle[1] = fail
}
// new Promise2(() => {}) 这里也是一个hack,会触发上面的构造器 ---> resolveOrReject(resolveOrReject会等到下面逻辑都执行完才会触发)
handle[2] = new Promise2(() => {})
//缓存到数组中方便下一个循环执行
this.callbacks.push(handle)
//这样做就可以链式调用
return handle[2]
}
private resolveWithSelf() {
this.reject(new TypeError())
}
private resolveWithPromise(x) {
x.then(
result => { this.resolve(result) },
reason => { this.reject(reason) }
)
}
private getThen(x) {
let then
try {
then = x.then
} catch (e) {
return this.reject(e)
}
return then
}
private resolveWithThenable(x) {
try {
x.then(
y => { this.resolveWith(y) },
r => { this.reject(r) }
)
} catch (e) {
this.reject(e)
}
}
/**
* 解决new Promise(() => {}).then(res => {
* return {
* e.g 1 返回普通对象
* e.g 2 返回Promise对象
* }
* 目的是链式调用
* })
*/
private resolveWithObject(x) {
let then = this.getThen(x)
if (then instanceof Function) {
this.resolveWithThenable(x)
} else {
this.resolve(x)
}
}
//对resolve() 或者 reject() 返回值进行二次处理
private resolveWith(x) {
if (this === x) {
this.resolveWithSelf()
} else if (x instanceof Promise2) {
this.resolveWithPromise(x)
} else if (x instanceof Object) {
this.resolveWithObject(x)
} else {
this.resolve(x)
}
}
}
export default Promise2
// 封装的异步调用方法
function nextTick(fn) {
if (process !== undefined && typeof process.nextTick === "function") {
return process.nextTick(fn)
} else {
var counter = 1
var observer = new MutationObserver(fn)
var textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
counter = counter + 1
textNode.data = String(counter)
}
}
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
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
最后欢迎留言交流