es6 中的 Promise 可以简化 callback hell“回调地狱,回调套回调”造成的代码结构上的多级缩进
让代码看起来像同步的,消除多级缩进,从结构上简化代码(之后有 await 语法让代码看起来更“同步”)
消灭 if error 代码
消除回调地狱也可以用命名恰当的多个子函数化解
先来看一下 Promise 的 API
Promise 是一个类
类参数:就一个函数
类方法:all/allSettled/race/reject/resolve
对象属性:then(重要)/finally/catch
对象内部属性:state=pending(悬而未决)/fulfilled(成功)/rejected(失败)
这次的实现需要满足 Promise/A+的标准
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
|
class Promise2 {
state = 'pending'
callbacks = []
resolve(result) {
nextTick(() => {
if (this.state !== 'pending') return
this.state = 'fulfilled'
for (let handle of this.callbacks) {
if (typeof handle[0] === 'function') {
let x
try {
x = handle[0].call(undefined, result)
} catch (error) {
return handle[2].reject(error)
}
handle[2].resolveWith(x)
}
}
})
}
reject(reason) {
nextTick(() => {
if (this.state !== 'pending') return
this.state = 'rejected'
for (let handle of this.callbacks) {
if (typeof handle[1] === 'function') {
let x
try {
x = handle[1].call(undefined, reason)
} catch (error) {
return handle[2].resolveWith(x)
}
handle[2].resolveWith(x)
}
}
})
}
constructor(fn) {
if (typeof fn !== 'function') {
throw new Error('Promise的参数需要是一个函数')
}
fn(this.resolve.bind(this), this.reject.bind(this))
}
then(succeed?, fail?) {
let handle = []
if (typeof succeed === 'function') {
handle[0] = succeed
}
if (typeof fail === 'function') {
handle[1] = fail
}
handle[2] = new Promise2(() => {})
this.callbacks.push(handle)
return handle[2]
}
resolveWithSelf() {
this.reject(new TypeError('x should not be this'))
}
resolveWithPromise(x) {
x.then(
(result) => {
this.resolve(result)
},
(reason) => {
this.reject(reason)
}
)
}
getThen(x) {
let then
try {
then = x.then
} catch (error) {
this.reject(error)
}
return then
}
resolveWithThenable(x) {
try {
x.then(
(y) => {
this.resolveWith(y)
},
(r) => {
this.reject(r)
}
)
} catch (error) {
this.reject(error)
}
}
resolveWithObject(x) {
let then = this.getThen(x)
if (then instanceof Function) {
this.resolveWithThenable(x)
} else {
this.resolve(x)
}
}
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)
}
}
|