Promise总共有三种状态,分别是pending,resolved,rejected。

  1. 状态变化是pending->resolved或者pending->rejected,且状态变化不可逆。
  2. pending不会触发then或者catch回调函数,resolved会触发then回调函数,rejected会触发catch回调函数。
  3. then正常返回resolved,里面有报错返回rejected;catch正常返回resolved,里面有报错返回rejected。

面试题

// 第一题
Promise.resolve().then(() => {
    console.log(1) //返回 resolved 状态的 promise,不执行catch
}).catch(() => {
    console.log(2)
}).then(() => {
    console.log(3)//返回 resolved 状态的 promise
})

结果为1,3

// 第二题
Promise.resolve().then(() => { 
    console.log(1)
    throw new Error('erro1') //原本应返回resolved状态的promise,但因为抛出异常,所以返回 rejected 状态的 promise,执行catch
}).catch(() => { 
    console.log(2) // 返回 resolved 状态的 promise,执行then
}).then(() => {
    console.log(3) // 返回 resolved 状态的 promise
})

结果为1,2,3

// 第三题
Promise.resolve().then(() => { 
    console.log(1)
    throw new Error('erro1') // 原本应返回resolved状态的promise,但因为抛出异常,返回 rejected 状态的 promise
}).catch(() => { 
    console.log(2) // 返回 resolved 状态的 promise,不执行catch
}).catch(() => {
    console.log(3)
})

结果为1,2

基于以上特性手写promise如下代码:

class MyPromise {
    state = 'pending' // 状态,'pending' 'fulfilled' 'rejected'
    value = undefined // 成功后的值
    reason = undefined // 失败后的原因

    resolveCallbacks = [] // pending 状态下,存储成功的回调
    rejectCallbacks = [] // pending 状态下,存储失败的回调

    constructor(fn) {
        const resolveHandler = (value) => {
            if (this.state === 'pending') {
                this.state = 'fulfilled'
                this.value = value
                this.resolveCallbacks.forEach(fn => fn(this.value))
            }
        }

        const rejectHandler = (reason) => {
            if (this.state === 'pending') {
                this.state = 'rejected'
                this.reason = reason
                this.rejectCallbacks.forEach(fn => fn(this.reason))
            }
        }

        try {
            fn(resolveHandler, rejectHandler)
        } catch (err) {
            rejectHandler(err)
        }
    }

    then(fn1, fn2) {
        fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
        fn2 = typeof fn2 === 'function' ? fn2 : (e) => e

        if (this.state === 'pending') {
            const p1 = new MyPromise((resolve, reject) => {
                this.resolveCallbacks.push(() => {
                    try {
                        const newValue = fn1(this.value)
                        resolve(newValue)
                    } catch (err) {
                        reject(err)
                    }
                })

                this.rejectCallbacks.push(() => {
                    try {
                        const newReason = fn2(this.reason)
                        reject(newReason)
                    } catch (err) {
                        reject(err)
                    }
                })
            })
            return p1
        }

        if (this.state === 'fulfilled') {
            const p1 = new MyPromise((resolve, reject) => {
                try {
                    const newValue = fn1(this.value)
                    resolve(newValue)
                } catch (err) {
                    reject(err)
                }
            })
            return p1
        }

        if (this.state === 'rejected') {
            const p1 = new MyPromise((resolve, reject) => {
                try {
                    const newReason = fn2(this.reason)
                    reject(newReason)
                } catch (err) {
                    reject(err)
                }
            })
            return p1
        }
    }

    // 就是 then 的一个语法糖,简单模式
    catch(fn) {
        return this.then(null, fn)
    }
}

MyPromise.resolve = function (value) {
    return new MyPromise((resolve, reject) => resolve(value))
}
MyPromise.reject = function (reason) {
    return new MyPromise((resolve, reject) => reject(reason))
}

MyPromise.all = function (promiseList = []) {
    const p1 = new MyPromise((resolve, reject) => {
        const result = [] // 存储 promiseList 所有的结果
        const length = promiseList.length
        let resolvedCount = 0

        promiseList.forEach(p => {
            p.then(data => {
                result.push(data)

                // resolvedCount 必须在 then 里面做 ++
                // 不能用 index
                resolvedCount++
                if (resolvedCount === length) {
                    // 已经遍历到了最后一个 promise
                    resolve(result)
                }
            }).catch(err => {
                reject(err)
            })
        })
    })
    return p1
}

MyPromise.race = function (promiseList = []) {
    let resolved = false // 标记
    const p1 = new Promise((resolve, reject) => {
        promiseList.forEach(p => {
            p.then(data => {
                if (!resolved) {
                    resolve(data)
                    resolved = true
                }
            }).catch((err) => {
                reject(err)
            })
        })
    })
    return p1
}

爱吃鸡蛋饼
55 声望8 粉丝