一步步实现一个Promise

1、前言

本篇文章,默认你已经知道什么是 Promise ,然后我会带你一步步的实现一个简易的 Promise。将会以循序渐进的方式,分步骤实现。

本文章相关代码地址:https://github.com/layouwen/blog_demo_lpromise

如果本文章对你有所帮助,请不要吝啬你的 Start 哦~

2、三种状态

此处代码,点击这里

Promise 它一共会有三种状态:

  1. pending
  2. fulfilled
  3. rejected

下面我们自己实现一个类,默认为 pending 状态,通过调用 resolve 或者 reject 改变其状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
}
}
console.log(new LPromise((resolve, reject) => console.log('pending'))) // pending 状态
const l1 = new LPromise((resolve, reject) => {
resolve('我调用了resolve')
})
console.log(l1) // fulfilled 状态
const l2 = new LPromise((resolve, reject) => {
reject('我调用了reject')
})
console.log(l2) // rejected 状态

3、实现 then 参数回调

此处代码,点击这里

返回的 Promise ,可以通过使用 then 传递成功和失败的回调。

通过 then 接收了两个回调。实现了分别调用回调的内容。但是发现,他们两个都会执行。

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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
}
/* new content start */
then(onResolve, onReject) {
onResolve()
onReject()
}
/* new content end */
}
const l1 = new LPromise((resolve, reject) => resolve())
l1.then(
res => console.log('res'),
err => console.log('err')
)

对执行时机进行调整。使其在调用 resolve 或 reject 才执行相关的回调

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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
/* new content start */
this.cbResolve() // 报错
/* new content end */
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
/* new content start */
this.cbReject() // 报错
/* new content end */
}
then(onResolve, onReject) {
/* new content start */
this.cbResolve = onResolve
this.cbReject = onReject
/* new content end */
}
}
const l1 = new LPromise((resolve, reject) => resolve())
l1.then(
res => console.log('res'),
err => console.log('err')
)

改装后,发现 resolve 和 reject 的执行时间比 then 的回调要快。导致无法执行 then 中的回调。我们需要对 resolve 和 reject 中执行回调的部分进行 延迟执行。可以使用 setTimeout 进行延迟

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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
/* new content start */
setTimeout(() => this.cbResolve())
/* new content end */
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
/* new content start */
setTimeout(() => this.cbReject())
/* new content end */
}
then(onResolve, onReject) {
this.cbResolve = onResolve
this.cbReject = onReject
}
}
const l1 = new LPromise((resolve, reject) => resolve())
l1.then(
res => console.log('res'),
err => console.log('err')
)

考虑到 微任务 和 宏任务。我们可以使用 MutationObserver 替代 setTimeout

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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
/* new content start */
const run = () => this.cbResolve()
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
/* new content end */
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
/* new content start */
const run = () => this.cbReject()
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
/* new content end */
}
then(onResolve, onReject) {
this.cbResolve = onResolve
this.cbReject = onReject
}
}
const l1 = new LPromise((resolve, reject) => resolve())
l1.then(
res => console.log('res'),
err => console.log('err')
)

4、链式调用

此处代码,点击这里

在原本的 Promise 中。我们是可以使用 then 链式调用。意味着每个 then 都返回一个新的 Promise

因为支持链式。所以我们之前的 cbResolvecbReject 就不能单单保存一个回调。要改回一个数组,将每一个 then 中的回调。都保存到回调队列中。等待调用 resolve 或者 reject 后才执行所有回调函数。

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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
/* new content start */
this.cbResolveQueue = []
this.cbRejectQueue = []
/* new content end */
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
/* new content start */
const run = () => {
let cbFn
while ((cbFn = this.cbResolveQueue.shift())) {
cbFn && cbFn()
}
}
/* new content end */
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
/* new content start */
const run = () => {
let cbFn
while ((cbFn = this.cbRejectQueue.shift())) {
cbFn && cbFn()
}
}
/* new content end */
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
then(onResolve, onReject) {
/* new content start */
return new LPromise((resolve, reject) => {
const cbResolve = () => {
onResolve && onResolve()
resolve()
}
this.cbResolveQueue.push(cbResolve)
const cbReject = () => {
onReject && onReject()
reject()
}
this.cbRejectQueue.push(cbReject)
})
/* new content end */
}
}
const l1 = new LPromise((resolve, reject) => resolve())
l1.then(
res => console.log('res'),
err => console.log('err')
).then(
res => console.log('res'),
err => console.log('err')
)

此时我们已经完成了链式调用,但是我们会发现,此时如果返回一个新的 Promise ,却无法获取 Promise 的结果。所以我们得加一些判断条件。我们也会发现,此时此刻我们无法接收到 reserr 的参数。所以我们也要完善一下参数传递问题。

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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
this.cbResolveQueue = []
this.cbRejectQueue = []
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
const run = () => {
let cbFn
while ((cbFn = this.cbResolveQueue.shift())) {
/* new content start */
cbFn && cbFn(res)
/* new content end */
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
const run = () => {
let cbFn
while ((cbFn = this.cbRejectQueue.shift())) {
/* new content start */
cbFn && cbFn(err)
/* new content end */
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
then(onResolve, onReject) {
return new LPromise((resolve, reject) => {
/* new content start */
const cbResolve = res => {
const resolveRes = onResolve && onResolve(res)
if (resolveRes instanceof LPromise) {
resolveRes.then(resolve)
} else {
resolve(res)
}
}
/* new content end */
this.cbResolveQueue.push(cbResolve)
/* new content start */
const cbReject = err => {
onReject && onReject(err)
reject(err)
}
/* new content end */
this.cbRejectQueue.push(cbReject)
})
}
}
const l1 = new LPromise((resolve, reject) => resolve('我是传入的 resolve 数据'))
l1.then(
res => {
console.log('第一个then的res', res)
return new LPromise((resolve, reject) => resolve('返回的Promise'))
},
err => console.log('第一个then的err', err)
)
.then(
res => console.log('第二个then的res', res),
err => console.log('第二个then的err', err)
)
.then(
res => console.log('第三个then的res', res),
err => console.log('第三个then的err', err)
)

到现在我们已经实现了 then 的链式调用

5、实现 catch 方法

此处代码,点击这里

在调用 catch 的时候自动在回调队列中添加一个错误回调函数。

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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
this.cbResolveQueue = []
this.cbRejectQueue = []
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
const run = () => {
let cbFn
while ((cbFn = this.cbResolveQueue.shift())) {
cbFn && cbFn(res)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
const run = () => {
let cbFn
while ((cbFn = this.cbRejectQueue.shift())) {
cbFn && cbFn(err)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
then(onResolve, onReject) {
return new LPromise((resolve, reject) => {
const cbResolve = res => {
const resolveRes = onResolve && onResolve(res)
if (resolveRes instanceof LPromise) {
resolveRes.then(resolve)
} else {
resolve(res)
}
}
this.cbResolveQueue.push(cbResolve)
const cbReject = err => {
onReject && onReject(err)
reject(err)
}
this.cbRejectQueue.push(cbReject)
})
}
/* new content start */
catch(err) {
this.then(undefined, err)
}
/* new content end */
}
const p1 = new LPromise((resolve, reject) => reject('我是p1的错误信息'))
p1.then(res => console.log(res)).catch(err => console.log(err))

6、resolve 和 reject 静态方法

此处代码,点击这里

这两个静态方法比较简单。只需要返回一个固定状态的 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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
this.cbResolveQueue = []
this.cbRejectQueue = []
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
const run = () => {
let cbFn
while ((cbFn = this.cbResolveQueue.shift())) {
cbFn && cbFn(res)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
const run = () => {
let cbFn
while ((cbFn = this.cbRejectQueue.shift())) {
cbFn && cbFn(err)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
then(onResolve, onReject) {
return new LPromise((resolve, reject) => {
const cbResolve = res => {
const resolveRes = onResolve && onResolve(res)
if (resolveRes instanceof LPromise) {
resolveRes.then(resolve)
} else {
resolve(res)
}
}
this.cbResolveQueue.push(cbResolve)
const cbReject = err => {
onReject && onReject(err)
reject(err)
}
this.cbRejectQueue.push(cbReject)
})
}
/* new content start */
static resolve(res) {
return new LPromise(resolve => resolve(res))
}
static reject(err) {
return new LPromise((undefined, reject) => reject(err))
}
/* new content end */
}
const p1 = LPromise.resolve('成功')
console.log(p1)
const p2 = LPromise.reject('失败')
console.log(p2)

7、实现 finally 方法

此处代码,点击这里

这个与 catch 类似的实现,只需要保证不管成功还是失败都执行里面的回调。

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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
this.cbResolveQueue = []
this.cbRejectQueue = []
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
const run = () => {
let cbFn
while ((cbFn = this.cbResolveQueue.shift())) {
cbFn && cbFn(res)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
const run = () => {
let cbFn
while ((cbFn = this.cbRejectQueue.shift())) {
cbFn && cbFn(err)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
then(onResolve, onReject) {
return new LPromise((resolve, reject) => {
const cbResolve = res => {
const resolveRes = onResolve && onResolve(res)
if (resolveRes instanceof LPromise) {
resolveRes.then(resolve)
} else {
resolve(res)
}
}
this.cbResolveQueue.push(cbResolve)
const cbReject = err => {
onReject && onReject(err)
reject(err)
}
this.cbRejectQueue.push(cbReject)
})
}
catch(err) {
this.then(undefined, err)
}
/* new content start */
finally(callback) {
this.then(callback, callback)
}
/* new content end */
static resolve(res) {
return new LPromise(resolve => resolve(res))
}
static reject(err) {
return new LPromise((undefined, reject) => reject(err))
}
}
const p1 = new LPromise((resolve, reject) => reject('我是p1的错误信息'))
p1.then(
res => console.log(res),
err => console.log(err)
).finally(() => console.log('finally'))

8、实现 race 方法

此处代码,点击这里

race 就是返回最先执行成功的结果。不管是成功还是失败。这样我们只需要遍历该 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
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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
this.cbResolveQueue = []
this.cbRejectQueue = []
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
const run = () => {
let cbFn
while ((cbFn = this.cbResolveQueue.shift())) {
cbFn && cbFn(res)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
const run = () => {
let cbFn
while ((cbFn = this.cbRejectQueue.shift())) {
cbFn && cbFn(err)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
then(onResolve, onReject) {
return new LPromise((resolve, reject) => {
const cbResolve = res => {
const resolveRes = onResolve && onResolve(res)
if (resolveRes instanceof LPromise) {
resolveRes.then(resolve)
} else {
resolve(res)
}
}
this.cbResolveQueue.push(cbResolve)
const cbReject = err => {
onReject && onReject(err)
reject(err)
}
this.cbRejectQueue.push(cbReject)
})
}
catch(err) {
this.then(undefined, err)
}
finally(callback) {
this.then(callback, callback)
}
static resolve(res) {
return new LPromise(resolve => resolve(res))
}
static reject(err) {
return new LPromise((undefined, reject) => reject(err))
}
/* new content start */
static race(promiseArr) {
return new LPromise((resolve, reject) => {
let isContinue = true
promiseArr.forEach(promise => {
promise.then(
res => {
if (isContinue) {
isContinue = false
resolve(res)
}
},
err => {
if (isContinue) {
isContinue = false
reject(err)
}
}
)
})
})
}
/* new content end */
}
const p1 = new LPromise((resolve, reject) => setTimeout(() => resolve(1), 200))
const p2 = new LPromise((resolve, reject) => setTimeout(() => reject(2), 1000))
const p3 = new LPromise((resolve, reject) => setTimeout(() => resolve(3), 3000))
LPromise.race([p1, p2, p3]).then(
res => console.log('res', res),
err => console.log('err', err)
)

9、实现 all 方法

此处代码,点击这里

all 方法当所有 Promise 都成功时返回所有结果的数组,否则返回第一个失败的结果。我们只需要遍历该 Promise 数组。定义个变量存放当前 res 的长度。如果长度等于数组的长度,我们就 resolve 出去。否则发现第一个失败的时候,直接 reject

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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
this.cbResolveQueue = []
this.cbRejectQueue = []
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
const run = () => {
let cbFn
while ((cbFn = this.cbResolveQueue.shift())) {
cbFn && cbFn(res)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
const run = () => {
let cbFn
while ((cbFn = this.cbRejectQueue.shift())) {
cbFn && cbFn(err)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
then(onResolve, onReject) {
return new LPromise((resolve, reject) => {
const cbResolve = res => {
const resolveRes = onResolve && onResolve(res)
if (resolveRes instanceof LPromise) {
resolveRes.then(resolve)
} else {
resolve(res)
}
}
this.cbResolveQueue.push(cbResolve)
const cbReject = err => {
onReject && onReject(err)
reject(err)
}
this.cbRejectQueue.push(cbReject)
})
}
catch(err) {
this.then(undefined, err)
}
finally(callback) {
this.then(callback, callback)
}
static resolve(res) {
return new LPromise(resolve => resolve(res))
}
static reject(err) {
return new LPromise((undefined, reject) => reject(err))
}
static race(promiseArr) {
return new LPromise((resolve, reject) => {
let isContinue = true
promiseArr.forEach(promise => {
promise.then(
res => {
if (isContinue) {
isContinue = false
resolve(res)
}
},
err => {
if (isContinue) {
isContinue = false
reject(err)
}
}
)
})
})
}
/* new content start */
static all(promiseArr) {
return new LPromise((resolve, reject) => {
const resArr = []
const length = promiseArr.length
promiseArr.forEach(p => {
p.then(
res => {
resArr.push(res)
if (resArr.length === length) {
resolve(resArr)
}
},
err => reject(err)
)
})
})
}
/* new content end */
}
const p1 = new LPromise((resolve, reject) => setTimeout(() => resolve(1), 200))
const p2 = new LPromise((resolve, reject) => setTimeout(() => reject(2), 1000))
const p3 = new LPromise((resolve, reject) => setTimeout(() => reject(3), 3000))
LPromise.all([p1, p2, p3]).then(
res => console.log('res', res),
err => console.log('err', err)
)

10、实现 allSettled 方法

此处代码,点击这里

该方法与 all 类似。只是这个方法不管成功或失败,只要该 Promise 数组执行完毕。就会返回所有结果。我们只需要判断执行过的 Promise 长度是否等于数组长度。当一致时就直接 resolve。并且每次执行的时候,将返回值以指定格式的对象保存到返回的 res 中。

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
class LPromise {
constructor(callbackFn) {
this['[[PromiseState]]'] = 'pending'
this['[[PromiseResult]]'] = undefined
this.cbResolveQueue = []
this.cbRejectQueue = []
callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
}
#resolve(res) {
this['[[PromiseState]]'] = 'fulfilled'
this['[[PromiseResult]]'] = res
const run = () => {
let cbFn
while ((cbFn = this.cbResolveQueue.shift())) {
cbFn && cbFn(res)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
#reject(err) {
this['[[PromiseState]]'] = 'reject'
this['[[PromiseResult]]'] = err
const run = () => {
let cbFn
while ((cbFn = this.cbRejectQueue.shift())) {
cbFn && cbFn(err)
}
}
const ob = new MutationObserver(run)
ob.observe(document.body, { attributes: true })
document.body.setAttribute('lpromise', 'layouwen')
}
then(onResolve, onReject) {
return new LPromise((resolve, reject) => {
const cbResolve = res => {
const resolveRes = onResolve && onResolve(res)
if (resolveRes instanceof LPromise) {
resolveRes.then(resolve)
} else {
resolve(res)
}
}
this.cbResolveQueue.push(cbResolve)
const cbReject = err => {
onReject && onReject(err)
reject(err)
}
this.cbRejectQueue.push(cbReject)
})
}
catch(err) {
this.then(undefined, err)
}
finally(callback) {
this.then(callback, callback)
}
static resolve(res) {
return new LPromise(resolve => resolve(res))
}
static reject(err) {
return new LPromise((undefined, reject) => reject(err))
}
static race(promiseArr) {
return new LPromise((resolve, reject) => {
let isContinue = true
promiseArr.forEach(promise => {
promise.then(
res => {
if (isContinue) {
isContinue = false
resolve(res)
}
},
err => {
if (isContinue) {
isContinue = false
reject(err)
}
}
)
})
})
}
static all(promiseArr) {
return new LPromise((resolve, reject) => {
const resArr = []
const length = promiseArr.length
promiseArr.forEach(p => {
p.then(
res => {
resArr.push(res)
if (resArr.length === length) {
resolve(resArr)
}
},
err => reject(err)
)
})
})
}
/* new content start */
static allSettled(promiseArr) {
return new LPromise(resolve => {
const resArr = new Array(promiseArr.length)
let num = 0
promiseArr.forEach(p => {
let obj = {}
p.then(
res => {
obj.status = 'fulfilled'
obj.value = res
resArr[num] = obj
num++
if (num === resArr.length) resolve(resArr)
},
err => {
obj.status = 'rejected'
obj.reason = err
resArr[num] = obj
num++
if (num === resArr.length) resolve(resArr)
}
)
})
})
}
/* new content end */
}
const p1 = new LPromise((resolve, reject) => setTimeout(() => resolve(1), 200))
const p2 = new LPromise((resolve, reject) => setTimeout(() => reject(2), 1000))
const p3 = new LPromise((resolve, reject) => setTimeout(() => reject(3), 3000))
LPromise.allSettled([p1, p2, p3]).then(
res => console.log('res', res),
err => console.log('err', err)
)

End

本文章实现的 Promise 不够完善,只是大概把实现原理带大家过一遍。Promise 的源码不是由 js 写的,所以我们只能尽可能使用 js 模仿。欢淫各位大佬补充更完善的版本。

交流学习~

微信:gdgzyw
github: www.github.com/layouwen