核心代码

3/15/2022 js

# 核心代码

class Promise {
	constructor(executor) {
        // Promise的状态
		this.status = 'pending'
        // Promise状态对应的值
		this.value = undefined
		this.onResolvedCallback = []
		this.onRejectedCallback = []

        // 将Promise的状态转化从pending转化为fulfilled
		const resolve = (value) => {
			if (this.status === 'pending') {
                this.status = 'fulfilled'
                this.value = value
                this.onResolvedCallback.forEach(callback => callback())
			}
		}

        // 将Promise的状态转化从pending转化为rejected
		const reject = (reason) => {
			if (this.status === 'pending') {
				this.status = 'rejected'
				this.value = reason
				this.onRejectedCallback.forEach(callback => callback())
			}
		}
        
		try {
            // 执行传入的函数
			executor(resolve, reject)
		} catch (error) {
			reject(error)
		}
	}

	then(onResolve, onReject) {
        // then函数需要返回一个新的Promise
		return new Promise((resolve, reject) => {
            // 和事件不同。事件先触发再监听则不会触发回调函数
            // 而Promise即使状态已经转化,也会触发回调
			if (this.status === 'fulfilled') {
                // 通过setTimeout实现异步。
                // 与真实的实现不同,setTimeout的回调会放进macro task队列。
                // 而真实的实现,then的回调会放进micro task队列。
				setTimeout(() => {
                    // onResolve的函数返回值会被新的Promise进行resolve
                    // var b = a.then(data => {
					//    return data * data
					//	})
                    // 此处若a的内部值为10,则b的内部值为100
					resolve(onResolve(this.value))
				})
			}
			else if (this.status === 'rejected') {
				setTimeout(() => {
                    // 注意这里也是resolve,不要误以为是 reject(onReject(this.value))
					resolve(onReject(this.value))
				})
			}
			else if (this.status === 'pending') {
				this.onResolvedCallback.push(() => {
					setTimeout(() => {
						resolve(onResolve(this.value))
					})
				})

				this.onRejectedCallback.push(() => {
					setTimeout(() => {
						resolve(onReject(this.value))
					})
				})
			}
		})
	}
}
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

好,核心功能实现了,再一点点加功能。

一:我们有的时候会resolve一个Promise,例如

var p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(1)
    }, 2000)
})
var p2 = new Promise((resolve, reject) => {
    resolve(p1)
})

// 或者

var p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(1)
    }, 2000)
})

var p2 = a.then(data => {
    return p1
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

我们希望p2的状态以及内部值和p1保持一致。那么我们稍微修改一下代码。

const resolve = (value) => {
    if (this.status === 'pending') {
        // 如果resolve的参数是Promise实例,则状态与其保持一致
        if (value instanceof Promise) {
            value.then((data) => {
                resolve(data)
            }, (reason) => {
                reject(reason)
            })
        } else {
            this.status = 'fulfilled'
            this.value = value
            this.onResolvedCallback.forEach(callback => callback())
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

二 异常的捕获

var p1 = new Promise((resolve, reject) => {
    reject(new Error())
})
var p2 = p1.then((data) => {
    
}, (reason) => {
    
})
1
2
3
4
5
6
7
8

当这里p1状态为rejected时,可能有人会误以为p2也是rejected,然而实际是fulfilled。

只有当onFulfilledonRejected抛出了异常e, 则p2应当以ereason转化成rejected

所以我们需要对可能的异常进行捕获。

setTimeout(() => {
    try {
        resolve(onResolve(this.value))
    } catch (e) {
        reject(e)
    }
})
1
2
3
4
5
6
7

  1. 如果 onFulfilled 不是一个函数且promise1已经fulfilled,则promise2必须以promise1的值fulfilled.

  2. 如果 OnReject 不是一个函数且promise1已经rejected, 则promise2必须以相同的reason被reject.

if (typeof onReject !== 'function') {
    reject(this.value)
} else {
    resolve(onReject(this.value))
}
// ...
if (typeof onResolve !== 'function') {
    resolve(this.value)
} else {
    resolve(onResolve(this.value))	
}
1
2
3
4
5
6
7
8
9
10
11

代替原先的

resolve(onReject(this.value))
// ...
resolve(onResolve(this.value))	
1
2
3

那么我们现在的代码如下

# 复杂版

class Promise {
	constructor(executor) {
		if (typeof executor !== 'function') {
			throw new TypeError("Promise resolver undefined is not a function")
		}
		this.status = 'pending'
		this.value = undefined
		this.onResolvedCallback = []
		this.onRejectedCallback = []

		const resolve = (value) => {
			if (this.status === 'pending') {
				if (value instanceof Promise) {
					value.then((data) => {
						resolve(data)
					}, (reason) => {
						reject(reason)
					})
				} else {
					this.status = 'fulfilled'
					this.value = value
					this.onResolvedCallback.forEach(callback => callback())
				}
			}
		}

		const reject = (reason) => {
			if (this.status === 'pending') {
				this.status = 'rejected'
				this.value = reason
				this.onRejectedCallback.forEach(callback => callback())
			}
		}
		try {
			executor(resolve, reject)
		} catch (error) {
			reject(error)
		}
	}

	then(onResolve, onReject) {
		return new Promise((resolve, reject) => {
			if (this.status === 'fulfilled') {
				setTimeout(() => {
					if (typeof onResolve !== 'function') {
						resolve(this.value)
					} else {
						try {
							resolve(onResolve(this.value))
						} catch (error) {
							reject(error)
						}
							
					}
				})
			}
			else if (this.status === 'rejected') {
				setTimeout(() => {
					if (typeof onReject !== 'function') {
						reject(this.value)
					} else {
						try {
							resolve(onReject(this.value))
						} catch (error) {
							reject(error)
						}
						
					}
				})
			}
			else if (this.status === 'pending') {
				this.onResolvedCallback.push(() => {
					setTimeout(() => {
						if (typeof onResolve !== 'function') {
							resolve(this.value)
						} else {
							try {
								resolve(onResolve(this.value))
							} catch (error) {
								reject(error)
							}
						}
					})
				})

				this.onRejectedCallback.push(() => {
					setTimeout(() => {
						if (typeof onReject !== 'function') {
							reject(this.value)
						} else {
							try {
								resolve(onReject(this.value))
							} catch (error) {
								reject(error)
							}
						}
					})
				})
			}
		})
	}
}

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

# 实现catch函数

catch(onReject) {
    return this.then(null, onReject)
}
1
2
3

# 实现finally函数

finally(cb) {
	let P = this.constructor
	return this.then(
		value => P.resolve(cb()).then(() => value),
		reason => P.resolve(cb()).then(() => {throw reaon})
	)
}
1
2
3
4
5
6
7

# 实现all函数

static all(promiseArr) {
    return new Promise((resolve, reject) => {
        let res = []
        let length = promiseArr.length
        let count = 0
        promiseArr.forEach((promise, index) => {
            promise.then(value => {
                res[index] = value
                count++
                if (count === length) {
                    resolve(res)
                }
            }, (reason) => {
                reject(reason)
            })
        })
    })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 实现race函数

static race(promiseArr) {
    return new Promise((resolve, reject) => {
        promiseArr.forEach((promise) => {
            promise.then(value => {
                resolve(value)
            }, reason => {
                reject(reason)
            })
        })
    })
}
1
2
3
4
5
6
7
8
9
10
11

用代码测试一下

// example

let p1 = new Promise((resolve,reject)=>{
    setTimeout(() => {
        console.log(1);
        resolve(1)
    }, 3000)
})
let p2 = new Promise((resolve,reject)=>{
    setTimeout(() => {
        console.log(2);
        resolve(2)
    }, 2000)
})
let p3 = new Promise((resolve,reject)=>{
    setTimeout(() => {
        console.log(3);
        resolve(3)
    }, 1000)
})

Promise.all([p1, p2, p3])
.then(console.log)
.catch(console.error)

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
Last Updated: 9/7/2022, 11:32:53 PM