JS Asynchronous Advancement 5:手書きの約束

私たちの手書きのプロミスは主に次の機能を実装しています

  • 初期化と非同期呼び出し

  • その後、チェーンコールをキャッチ

  • API .resolve .reject .all .race(基本的なpromise APIを実装します)

<!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>
复制代码

約束の基礎

  1. Promiseはクラスです

  2. Promiseクラスが実行されると、すぐに実行されるエグゼキュータ関数が渡されます。

  3. 約束には3つの状態があります

    • 保留中
    • 満たされた
    • 拒否されました
  4. Promiseの状態は、一度決定されると変更できず、状態は次の方法でのみ決定できます。

    • 保留中=>実行済み
    • 保留中=>拒否
  5. 状態の変化は、resolveメソッドとrejectメソッドによって変更されます

  6. thenメソッドが内部で行うのは、状態の判断です。

    • Fulfilled状態の場合、正常なコールバックを実行します
    • 拒否状態の場合は、失敗したコールバックを実行します
  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