JS异步进阶之5:手写Promise

我们手写Promise 主要实现一下几个功能

  • 初始化&异步调用

  • then catch 链式调用

  • API .resolve .reject .all .race(实现基本的promiseAPI)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MyPromise</title>
</head>
<body>
    <h1>MyPromise</h1>

    <script src="./MyPromise.js"></script>
    <script>
        const p1 = new MyPromise((resolve, reject) => {
            // resolve(100)
            // reject('错误信息...')
            setTimeout(() => {
                resolve(100)
            }, 1000)
        })

        // const p11 = p1.then(data1 => {
        //     console.log('data1', data1)
        //     return data1 + 1
        // })
        // const p12 = p11.then(data2 => {
        //     console.log('data2', data2)
        //     return data2 + 2
        // })
        // const p13 = p12.catch(err => console.error(err))

        const p2 = MyPromise.resolve(200)
        const p3 = MyPromise.resolve(300)
        const p4 = MyPromise.reject('错误信息...')
        // const p5 = MyPromise.all([p1, p2, p3]) // 传入 promise 数组,等待所有的都 fulfilled 之后,返回新 promise ,包含前面所有的结果
        // p5.then(result => console.log('all result', result))
        const p6 = MyPromise.race([p1, p2, p3]) // 传入 promise 数组,只要有一个 fulfilled 即可返回
        p6.then(result => console.log('race result', result))

    </script>
</body>
</html>
复制代码

Promise的基本原理

  1. Promise是一个类

  2. Promise类在执行时会传入一个执行器函数,该函数会立即执行

  3. Promise具有三种状态

    • Pending
    • Fulfilled
    • Rejected
  4. Promise状态一旦确定就不可以改变,且状态只能由

    • Pending => Fulfilled
    • Pending => Rejected
  5. 状态的改变由resolve,reject两个方法改变

  6. then方法内部做的事情是状态判断

    • 如果是Fulfilled状态则执行成功的回调
    • 如果是Rejected状态则执行失败的回调
  7. Promise的链式调用需要在then方法中返回一个Promise实例

代码实现

/**
 * @description MyPromise
 * @author 双越
 */

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
}

复制代码

猜你喜欢

转载自juejin.im/post/7078325423460843551