手写Promise.all方法和race方法

132 阅读2分钟

在面试中,手写promise.all方法是很常见的,我也对这一部分知识点掌握的不够牢固,现在就写一篇文章,来好好复盘一下这一部分的手写该如何去写

首先还是要看一下MDN中对Promise.all方法的定义:

QQ_1740209556021.png

可以看到,all方法接受一个可迭代对象作为输入,并返回一个promise,什么是可迭代对象呢 可迭代对象就是一种支持迭代操作的数据结构,我们可以简单认为支持for...of 循环来遍历对象中的元素的就是可迭代对象,例如:

1.数组(Array) 2.字符串(string) 3.集合(Set) 4.映射(Map)

这也就是为什么,我们在手写all方法时,不能使用lengthsize来判断传入对象的数量,所以要使用for...of搭配count变量来实现,这也是其中比较难记忆的一点。

下面直接展示代码内容吧

Promise.myAll = function (fn) {
    let res, rej
    const p = new Promise((resolve, reject) => {
        res = resolve
        rej = reject
        // 通过 count 和 for of 来判断传入 myAll 里 fn 的对象数量
        // 官方说法promise.all的输入是一个可迭代对象
        // (不能用 length 和 size ,因为如果传入的是 Set 或 Map等就不好判断,但是for of可以用来判断可迭代对象)
        let count = 0
        const result = []
        // 使用i来获取fn里数据的下标
        let i = 0
        // 定义完成promise的数量
        let fulfilledCouont = 0
        for (const item of fn) {
            const index = i
            i++
            count++
            // 把每一项变成promise
            Promise.resolve(item).then((data) => {
                // 把运行结果存进result
                result[index] = data
                fulfilledCouont++
                // 若所有promise都已经完成,就返回一个成功的promise
                if (fulfilledCouont === count) {
                    res(result)
                }
                // 如果有失败的,就直接返回失败promise
            }, rej)
        }
        // 如果传递的是空数组,直接完成
        if (count === 0) {
            res(result)
        }
    })
    return p
}

const p1 = Promise.resolve(666)

Promise.myAll([1, 2, 3, p1]).then(data => {
    console.log(data)
},
    err => {
        console.log(err)
    })

而promise.race方法就较为简单了,在传入race方法的可迭代对象里,只要有一个成功就接受那个成功的结果

代码直接展示

Promise.myRace = function (fn) {
    const p = new Promise((resolve, reject) => {
        for (const item of fn) {
            Promise.resolve(item).then(resolve, reject)
        }
    })
    return p
}