Promise 原理手撕!看完就会辣!

172 阅读3分钟

前言

经过上一篇的学习,你肯定已经会了 Promise 的基本使用!# 细嚼慢咽(一)!适合初学者的 Promise 基础教程指南!年前的饺子得吃!那么接下来,就跟着我,手撕 Promise 方法,掌握运行的原理!吊打面试官!

resolve()

我们知道 resolve(params) 方法会把 params 传给下一次 then(val) 中的 val。

而 params 又有三种情况:

  • 普通的值,如 string、number、boolean
  • Promise 对象
  • 实现了 thenabale 方法的 JS 对象

而 resolve(params) 方法运行的原理就是:

  • 如果 params 是普通的值实现了 thenabale 方法的 JS 对象,则调用 Promise.resolve(params) 将 params 包裹成 Promise 并返回这个 Promise 对象
  • 如果 params 是 Promise,则直接返回即可

比如下面的例子:

//例子:
new Promise((resolve, reject) => {
    resolve('大家好,我是玺子哥!')
}).then(val => {
    console.log(val)
})

//输出:
大家好,我是玺子哥!

手写实现如下:

function myResolve(params) {
    //如果 params 是 Promise,则直接返回
    if (params instanceof Promise) return params
    //否则,将 params 包裹成 Promise,返回这个 Promise 对象
    return Promise.resolve(params)
}

运行结果如下:

1674035323988.png

all()

all(promiseArr) 是接受一组 promise 对象作为参数,根据下面两种情况,返回结果

  • 如果 promiseArr 里面的每一个 promise 对象都为 fulfilled,则把每一个 fulfilled 的结果添加到一个结果数组 res 中,返回 res
  • 如果 promiseArr 里面有一个 promise 对象为 rejected,则把 第一个 rejected 的值返回

实现如下:

function myAll(promiseArr) {
    let index = 0, res = []
    //返回的新的 Promise
    return new Promise((resolve, reject) => {
        //遍历 promiseArr,判断每一个 promise 的状态
        promiseArr.forEach(p => {
            //通过 Promise.resolve(p) 判断当前 p 的状态
            Promise.resolve(p).then(val => {
                index++
                //若为 fulfilled,则添加到 res 中 
                res.push(val)
                //如果相等,表示所有的 promise 均为 fulfilled,返回 res
                if (index === promiseArr.length) {
                    resolve(res)
                }
            }, err => {
                //如果有一个 promise 为 rejected
                reject(err)
            })
        })
    })
}

运行结果如下:

  • promiseArr 全是 fulfilled 时:

1674037270378.png

  • promiseArr 至少有一个是 rejected 时:

1674037406530.png

race()

race() 和 all() 类似,也是收集 promise 对象的数组 promiseArr 作为参数,只不过对于 race() 来说,谁先有状态,就先用谁的结果。

实现如下:

function myRace(promiseArr) {
    return new Promise((resolve, reject) => {
        //遍历 promiseArr
        promiseArr.forEach(p => {
            Promise.resolve(p).then(val => {
                //最先有结果的那个 promise 是 fulfilled
                resolve(val)
            }, err => {
                //最先有结果的那个 promise 是 rejected
                reject(err)
            })
        })
    })
}

运行结果如下:

1674037772868.png

allSettled()

allSettled() 方法和 all() 也类似,也接受 promiseArr 数组作为参数,它的规则如下:

  • 不管 promiseArr 里面的 promise 是 fulfilled 还是 rejected,都会把它的结果和状态都放进一个对象即:{status: 'fulfilled', value: ''},然后添加到结果数组 res 中。
  • 只要调用了 allSettled() 方法,原 Promise 对象的状态一定是 fulfilled

实现如下:

function myAllsettled(promiseArr) {
    let res = [], index = 0;
    return new Promise((resolve, reject) => {
        promiseArr.forEach(p => {
            Promise.resolve(p).then(val => {
                res.push({
                    status: 'fulfilled',
                    val
                })
                index++
            }, err => {
                res.push({
                    status: 'rejected',
                    val: err
                })
                index++
            }).finally(() => {
                //如果相等,则遍历完毕,且原 Promise 一定是 fulfilled
                if(index === promiseArr.length) resolve(res)
            })
        })
    })
}

运行结果如下:

1674039151577.png

any()

any() 同样和前面的几个类似,也接受 promiseArr 数组作为参数,规则如下:

  • promiseArr 里至少有一个为 fulfilled,则把成功的结果返回,原 Promise 对象为 fulfilled
  • promiseArr 里如果全是 rejected 或者 promiseArr为空数组,则会报错AggregateError

实现如下:

function myAny(promiseArr) {
    let index = 0;
    return new Promise((resolve, reject) => {
        promiseArr.forEach(p => {
            Promise.resolve(p).then(val => {
                resolve(val)
            }, err => {
                index++;
                if(index === promiseArr.length) {
                    reject(new AggregateError('All promises were rejected'))
                } 
            })
        })
    })
}

运行结果如下:

1674039048479.png

结尾

看到这里,恭喜你已经更进一步!

如果 这篇文章 对你有帮助,欢迎 点赞、收藏、评论,如果有 错误或还有疑问的地方,请 评论留言或者私信!