ES6新增了一个用于处理异步操作数据的一个原生API,能够解决回调地狱的产生

常用的方法

  • Promise.resolve()
  • Promise.reject()
  • Promise.then()
  • Promise.catch()
  • Promise.finally()
  • Promise.all()
  • Promise.race()
  • Promise.allSettled()
  • Promise.any()

接下来我们来使用代码来实现这些操作

实现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
const PANDING = 'panding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class Promise {
constructor(fn) {
this.state = PANDING
this.resolveVal = null
this.rejectVal = null
fn(this.resolve.bind(this), this.reject.bind(this))
}
resolve(value) {
let s = setInterval(() => {
if(this.state !== PANDING) {
s && clearInterval(s)
return
}
this.state = FULFILLED
this.resolveVal = value || this.resolveVal
},4)
}
reject(value) {
let s = setInterval(() => {
if(this.state !== PANDING) {
s && clearInterval(s)
return
}
this.state = REJECTED
this.rejectVal = value || this.rejectVal
})
}
}

这样就实现了一个简单的Promise方法,并且更改状态之后就不可以在修改状态了,并且用两个变量来接收resolvereject两个方法传入的值

  • Promise.then
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Promise.prototype.then = function(resolve, reject) {
let s = setInterval(() => {
if(this.state !== PANDING) {
s && clearInterval(s)
try {
let success = null
let fail = null
// 判断 传入参数的类型并绑定this
typeof resolve === 'function' && (success = getReturn(resolve.call(this, this.resolveVal)))
typeof reject === 'function' && (fail = getReturn(reject.call(this, this.rejectVal)))
if(success) return Promise.resolve(success)
if(fail) return Promise.resolve(fail)
return this
} catch (error) {
return Promise.reject(error)
}
}
},4)
}

调用 then 方法时判断一下传入的是否是函数,如果是函数就直接调用,并把成功的参数传入
最后的 return this 则是为了实现链式结构

  • Promise.catch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Promise.prototype.catch = function(reject) {
let s = setInterval(() => {
if(this.state !== PANDING) {
s && clearInterval(s)
try {
try {
let fail = null
typeof reject === 'function' && (fail = getReturn(reject.call(this, this.rejectVal)))
if(fail) return Promise.resolve(fail)
return this
} catch (error) {
return Promise.reject(error)
}
} catch (error) {
return Promise.reject(error)
}
}
},4)
}
  • Promise.finally
1
2
3
4
Promise.prototype.finally = function(fn) {
fn()
return this
}
  • Promise.resolve
1
2
3
4
Promise.resolve = function(value) {
if(value instanceof Promise) return value
return new Promise((resolve) => {resolve(value)})
}

这个稍微有些麻烦,我们需要判断传入的 value 是不是 Promise 类型的,如果是就可以直接返回,然后调用 .then 等方法,否则就需要我们创建一个 Promise 实例并返回

  • Promise.reject
1
2
3
4
Promise.reject = function(value) {
if(value instanceof Promise) return value
return new Promise((resolve, reject) => {reject(value)})
}

但是这里还有许多需要注意的地方,例如Promise.then中如果有 return 的话则需要以返回的状态和值为主,如果没有,就以上一次的状态和值为主
同时还需要对代码使用 try...catch... 进行容错处理,使得在 catch 中能够拿到错误信息

代码修改如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Promise.prototype.then = function(resolve, reject) {
try {
let success = null
let fail = null
// 判断 传入参数的类型并绑定this
typeof resolve === 'function' && (success = getReturn(resolve.call(this, this.resolveVal)))
typeof reject === 'function' && (fail = getReturn(reject.call(this, this.rejectVal)))
if(success) return Promise.resolve(success)
if(fail) return Promise.resolve(fail)
return this
} catch (error) {
return Promise.reject(error)
}
}

function getReturn(val) {
if(typeof val === 'function') return val()
return val
}

实现Promise高级语法

  • Promise.all
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
Promise.all = function(arr) {
try {
if(arr instanceof Array) {
return new Promise((resolve, reject) => {
let resolveVal = []
let isReject = false
for(let i = 0; i < arr.length; i++) {
let res = getReturn(arr[i])
if(res instanceof Promise) {
res.then(res1 => {
// 保证数组顺序返回正确
resolveVal[i] = res1
}).catch(err => {
reject(err)
isReject = true
})
}
else resolveVal.push(res)
if(isReject) break
}
resolve(resolveVal)
})
} else throw new Error('Promise.all must receive Array')
} catch (error) {
if(error instanceof Error) throw error
return Promise.reject(error)
}
}
  • Promise.race
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
Promise.race = function(arr) {
try {
if(arr instanceof Array) {
return new Promise((resolve, reject) => {
if(arr.length === 0) resolve()
for(let i = 0; i < arr.length; i++) {
let res = getReturn(arr[i])
if(res instanceof Promise) {
res.then(res1 => {
if(res1) {
resolve(res)
}
}).catch(err => {
if(err) {
reject(err)
}
})
} else {
resolve(res)
break;
}
}
})
} else throw new Error('Promise.all must receive Array')
} catch (error) {
if(error instanceof Error) throw error
return Promise.reject(error)
}
}
  • promise.allSettled
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
Promise.allSettled = function(arr) {
try {
if(arr instanceof Array) {
return new Promise((resolve, reject) => {
let resolveVal = []
let length = 0
if(arr.length === 0) resolve([])
for(let i = 0; i < arr.length; i++) {
let res = getReturn(arr[i])
if(res instanceof Promise) {
res.then(res1 => {
if(res1) {
resolveVal[i] = {
status: FULFILLED,
value: res1
}
if(++length === arr.length) resolve(resolveVal)
}
}).catch(err => {
if(err) {
resolveVal[i] = {
status: REJECTED,
value: err
}
if(++length === arr.length) resolve(resolveVal)
}
})
} else {
resolveVal[i] = {
status: FULFILLED,
value: res
}
if(++length === arr.length) resolve(resolveVal)
}
}
})
} else throw new Error('Promise.all must receive Array')
} catch (error) {
if(error instanceof Error) throw error
return Promise.reject(error)
}
}

这些代码中还是有很多的bug

全部代码

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
const PANDING = 'panding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class Promise {
constructor(fn) {
this.state = PANDING
this.resolveVal = null
this.rejectVal = null
fn(this.resolve.bind(this), this.reject.bind(this))
}
resolve(value) {
if(this.state !== PANDING) {
return
}
this.state = FULFILLED
this.resolveVal = value || this.resolveVal
}
reject(value) {
if(this.state !== PANDING) {
return
}
this.state = REJECTED
this.rejectVal = value || this.rejectVal
}
}
Promise.resolve = function(value) {
if(value instanceof Promise) return value
return new Promise((resolve) => {resolve(value)})
}
Promise.reject = function(value) {
if(value instanceof Promise) return value
return new Promise((resolve, reject) => {reject(value)})
}

Promise.all = function(arr) {
try {
if(arr instanceof Array) {
return new Promise((resolve, reject) => {
let resolveVal = []
let isReject = false
for(let i = 0; i < arr.length; i++) {
let res = getReturn(arr[i])
if(res instanceof Promise) {
res.then(res1 => {
resolveVal[i] = res1
}).catch(err => {
reject(err)
isReject = true
})
}
else resolveVal.push(res)
if(isReject) break
}
resolve(resolveVal)
})
} else throw new Error('Promise.all must receive Array')
} catch (error) {
if(error instanceof Error) throw error
return Promise.reject(error)
}
}
Promise.race = function(arr) {
try {
if(arr instanceof Array) {
return new Promise((resolve, reject) => {
if(arr.length === 0) resolve()
for(let i = 0; i < arr.length; i++) {
let res = getReturn(arr[i])
if(res instanceof Promise) {
res.then(res1 => {
if(res1) {
resolve(res)
}
}).catch(err => {
if(err) {
reject(err)
}
})
} else {
resolve(res)
}
}
})
} else throw new Error('Promise.all must receive Array')
} catch (error) {
if(error instanceof Error) throw error
return Promise.reject(error)
}
}
Promise.allSettled = function(arr) {
try {
if(arr instanceof Array) {
return new Promise((resolve, reject) => {
let resolveVal = []
let length = 0
if(arr.length === 0) resolve([])
for(let i = 0; i < arr.length; i++) {
let res = getReturn(arr[i])
if(res instanceof Promise) {
res.then(res1 => {
if(res1) {
resolveVal[i] = {
status: FULFILLED,
value: res1
}
if(++length === arr.length) resolve(resolveVal)
}
}).catch(err => {
if(err) {
resolveVal[i] = {
status: REJECTED,
value: err
}
if(++length === arr.length) resolve(resolveVal)
}
})
} else {
resolveVal[i] = {
status: FULFILLED,
value: res
}
if(++length === arr.length) resolve(resolveVal)
}
}
})
} else throw new Error('Promise.all must receive Array')
} catch (error) {
if(error instanceof Error) throw error
return Promise.reject(error)
}
}
Promise.prototype.then = function(resolve, reject) {
let s = setInterval(() => {
if(this.state !== PANDING) {
s && clearInterval(s)
try {
let success = null
let fail = null
// 判断 传入参数的类型并绑定this
typeof resolve === 'function' && (success = getReturn(resolve.call(this, this.resolveVal)))
typeof reject === 'function' && (fail = getReturn(reject.call(this, this.rejectVal)))
if(success) return Promise.resolve(success)
if(fail) return Promise.resolve(fail)
return this
} catch (error) {
return Promise.reject(error)
}
}
},4)
}
Promise.prototype.catch = function(reject) {
let s = setInterval(() => {
if(this.state !== PANDING) {
s && clearInterval(s)
try {
try {
let fail = null
typeof reject === 'function' && (fail = getReturn(reject.call(this, this.rejectVal)))
if(fail) return Promise.resolve(fail)
return this
} catch (error) {
return Promise.reject(error)
}
} catch (error) {
return Promise.reject(error)
}
}
},4)
}
Promise.prototype.finally = function(fn) {
fn()
return this
}

function getReturn(val) {
if(typeof val === 'function') return val()
return val
}