手写Promise.all解析

173 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

前言

Promise.allPromise api中为数不多开发中常用的api。你能够独立实现它吗?如果还不够清晰可以和我一起通过这篇文章了解它。

阅读这篇文章,需要你掌握的知识👇

  • Promise基本知识

其中Promise基础知识如果不了解或有遗忘的同学可以参考我这篇文章:《简单明了的Promise基本知识点》

规定

Promise.all:

  • Promise.all() 方法接收一个 promise 的 iterable 类型(注:Array,Map,Set 都属于 ES6iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有 promiseresolve 回调的结果是一个数组。
  • 如果传入的参数是一个空的可迭代对象,则返回一个已完成(fulfilled)状态的 Promise
  • 这个Promiseresolve 回调执行是在所有输入的 promiseresolve 回调都结束,或者输入的 iterable 里没有 promise 了的时候。
  • 它的 reject 回调执行是,只要任何一个输入的 promisereject 回调执行或者输入不合法的 promise 就会立即抛出错误,并且reject 的是第一个抛出的错误信息。

实现Promise.all

先创建一个函数名为myPromiseAll的函数,它接受一个promiseiterable 类型的参数👇

const myPromiseAll = function(promiseArray){
    if(Array.isArray(promiseArray)){
        
    }
}

那么参数类型不正确时应该干嘛呢?我们在参数类型不符合要求时,抛出一个错误👇

const myPromiseAll = function(promiseArray){
    if(Array.isArray(promiseArray)){
        
    }else{
        throw new Error('argument type is not iterable')
    }
}

接着,返回一个Promise实例:

const myPromiseAll = function(promiseArray){
    if(Array.isArray(promiseArray)){
        return new Promise((resolve,reject)=>{
             let result = []//输入的所有 `promise` 的 `resolve` 回调的结果是一个数组。
        })
    }else{
        throw new Error('argument type is not iterable')
    }
}
  • 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise
const myPromiseAll = function(promiseArray){
    if(Array.isArray(promiseArray)){
        return new Promise((resolve,reject)=>{
             if (promiseArray.length == 0){
                return Promise.resolve(promiseArray)
            }
            let result = []
        })
    }else{
        throw new Error('argument type is not iterable')
    }
}
  • 这个Promiseresolve 回调执行是在所有输入的 promiseresolve 回调都结束,或者输入的 iterable 里没有 promise 了的时候。
  • 它的 reject 回调执行是,只要任何一个输入的 promisereject 回调执行或者输入不合法的 promise 就会立即抛出错误,并且reject 的是第一个抛出的错误信息。
const myPromiseAll = function(promiseArray){
    if(Array.isArray(promiseArray)){
        return new Promise((resolve,reject)=>{
             if (promiseArray.length == 0){
                return Promise.resolve(promiseArray)
            }
            let result = []
            let count = 0 
             promiseArray.forEach((item,index)=>{
                Promise.resolve(item).then(value => {
                        count++//这里计数是为了判断所有的promise都是正确执行的
                        result[index] = value
                        count == promiseArray.length && resolve(result)//当所有的项都正确执行了,才会使这个promise执行
                    },
                    value => {
                        reject(value)//当出现错误时,就不累加count了,并抛出错误
                    } )
            })
        })
    }else{
        throw new Error('argument type is not iterable')
    }
}

大功告成🤩

测试

用一段测试代码来测试我们的myPromiseAll👇

const p1 = Promise.resolve(3);
const p2 = {
    then: function (onFulfill) {
        onFulfill('then函数')
    }
}
const p3 = 42;
​
myPromiseAll([p1, p2, p3]).then(result => {
    console.log('原生 all fulfilled :>> ', result);
}, reason => {
    console.log('原生 all rejected :>> ', reason)
})

输出

原生 all fulfilled :>>  [ 3, 'then函数', 42 ]

测试通过!

尾声

Promise.all的实现比较简单,不熟悉的同学多加练习就一定能掌握啦💪