7、简单手写 Promise

手写代码的思路为:先从使用开始进行分析。
Promise 的基本使用:

1
2
3
4
5
6
7
8
9
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
}, 2000)
}).then(res => {
console.log(res) // 'ok'
}, err => {
console.log(err)
})

根据基本使用,再写出注释:

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
// 1、Promise 为构造函数
// 2、入参为函数,该函数接受两个参数 resolve, reject,该函数是同步运行的
// 3、调用 resolve,则走向成功
// 4、调用 reject,则走向失败
// 5、.then 表明 new Promise 后会返回对象,并且该 then 接受两个参数
// 6、其他情况,它的状态有三个:pending、fulfilled、rejected

function MyPromise(fn) {
// 默认状态
this.state = 'pending'

// Promise 的值,通过 resolve、reject 传入的
this.value = ''

// 保存下 then 方法收到的函数
this.thenSuccessFun = []
this.thenFailFunFun = []


const resolve = (res) => {
this.state = 'fulfilled'
this.value = res

// 当 thenSuccessFun 有长度时,则需要执行里面的方法
if(this.thenSuccessFun.length) {
this.thenSuccessFun.forEach(fn => fn(this.value))
}
}

const reject = (err) => {
this.state = 'rejected'
this.value = err

// 当 thenFailFunFun 有长度时,则需要执行里面的方法
if(this.thenFailFunFun.length) {
this.thenFailFunFun.forEach(fn => fn(this.value))
}
}


// 执行传入的函数
fn(resolve, reject)

// then 方法
this.then = (successFun, failFun) => {
if(this.state === 'pending') {
// 调用 then 时,状态为 pending,表面 fn 里面还未调用 resolve/reject
// 则说明 fn 里面有异步操作,就不能直接调用 successFun/failFun
// 所以需要先存一下
if(typeof successFun === 'function') {
this.thenSuccessFun.push(successFun)
}

if(typeof failFun === 'function') {
this.thenFailFunFun.push(failFun)
}

} else if(this.state === 'fulfilled') {
// 调用 then 时,状态为 fulfilled,表面 fn 里面已调用 resolve
// 则可以直接调用 successFun
if(typeof successFun === 'function') {
successFun(this.value)
}

} else {
// 调用 then 时,状态为 rejected,表面 fn 里面已调用 reject
// 则可以直接调用 failFun
if(typeof failFun === 'function') {
failFun(this.value)
}
}
}
}


// 调试:
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
}, 2000)
}).then(res => {
console.log(res) // 'ok'
}, err => {
console.log(err)
})

// 打印结果:
// ok

上述展示了最基本的使用的实现,但是该实现与源码差的很远,只是让大家入个门,还要考虑各种边界与能力。

其他静态方法的实现原理:
**Promise.resolve(anyValue):Promise**成功的返回

1
2
3
4
5
6
7
8
9
Promise.resolve = (value) => {
// 当传入值为 Promise 时,直接返回
if(value instanceof Promise) return value

// 返回的还是个 Promise
return new Promise((resolve) => {
resolve(value)
})
}

**Promise.reject(anyValue):Promise**失败的返回

1
2
3
4
5
6
7
8
9
Promise.reject = (value) => {
// 当传入值为 Promise 时,直接返回
if(value instanceof Promise) return value

// 返回的还是个 Promise
return new Promise((resolve, reject) => {
reject(value)
})
}

**Promise.all(Array<Promise>):Promise**当所有的 Promise 成功时,则返回成功值的数组,否则返回第一个失败的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Promise.all = (PromiseArray) => {
// 返回的还是个 Promise
return new Promise((resolve, reject) => {
const result = [] // 存储成功值的数组

// 循环执行 promise,当错误时,直接 reject,当成功时,存储值
PromiseArray.forEach((promise, index) => {
// 最好改为 for 循环,这样可以中断

Promise.resolve(promise).then(res => {
result.push(res)

// 循环执行完毕时,则 resolve(result)
if(result.length - 1 === index) resolve(result)
}).catch(err => {
reject(err)
})
})
})
}

**Promise.allSettled(Array<Promise>):Promise**当所有的 Promise 执行完时,返回所有结果的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Promise.allSettled = (PromiseArray) => {
// 返回的还是个 Promise
return new Promise((resolve, reject) => {
const result = [] // 存储所有值的数组

// 循环执行 promise
PromiseArray.forEach((promise, index) => {
Promise.resolve(promise).then(res => {
result.push({state: 'success', value: res})

// 循环执行完毕时,则 resolve(result)
if(result.length - 1 === index) resolve(result)
}).catch(err => {
result.push({state: 'fali', value: err})

// 循环执行完毕时,则 resolve(result)
if(result.length - 1 === index) resolve(result)
})
})
})
}

**Promise.race(Array<Promise>):Promise**返回最先执行成功的值

1
2
3
4
5
6
7
8
9
Promise.allSettled = (PromiseArray) => {
// 返回的还是个 Promise
return new Promise((resolve, reject) => {
// 循环执行 promise
PromiseArray.forEach((promise, index) => {
Promise.resolve(promise).then(resolve).catch(reject)
})
})
}

7、简单手写 Promise
https://mrhzq.github.io/职业上一二事/前端面试/每日一题/7、简单手写 Promise/
作者
黄智强
发布于
2024年1月23日
许可协议