面试问能否手写 Promise 内置 API ?async,await 实现原理?手写一个 async,await 的实现

Promise内置API原理及实现(含async,await)

1、Promise.all

promise.all

接收一个Promise数组,数组中如有非Promise项,则此项当做成功

如果所有Promise都成功,则返回成功结果数组

如果有一个Promise失败,则返回这个失败结果

function all(PromiseArr){
    // 返回的结果数组
    let res = []
    // 记录完成了多少个promise
    let count = 0
    // Promise.all 返回一个promise结果数组
    return new Promise((resolve,reject)=>{
        // 增加完成的结果数组
        const addRes = (index,value)=>{
            res[index] = value
            count++
            // 当所有promise都完成后才处理
            if(count === PromiseArr.length) resolve(res)
        }

        // 循环遍历promise数组
        PromiseArr.forEach((item,index)=>{
            // 如果传来的是promise 则处理结果后添加到结果中
            if(item instanceof Promise){
                item.then(res=>addRes(index,res),err=>reject(err))
            }else{
                // 如果传的不是promise则直接加进结果中
                addRes(index,item)
            }
        })
    }) 
}

2、Promise.race

rece:

​ 接收一个Promise数组,数组中如有非Promise项,则此项当做成功

​ 哪个Promise最快得到结果,就返回那个结果,无论成功失败

function race(PromiseArr){
      
    return new Promise((resolve,reject)=>{
        PromiseArr.forEach((promise,index)=>{
            // 数组里的promise处理后返回
            if(promise instanceof Promise){
                promise.then(res=>resolve(res),err=>reject(err))
            }else{
                //如果不是promise 则直接返回
                // 加上queueMicrotask,让两个任务都进入微任务中,可以防止,如果传数值,在resolve后面,却输出数值
                queueMicrotask(()=>resolve(promise))
            }
        })
    })
}

3、Promise.allSettled

Promise.allSettled

​ 接收一个Promise数组,数组中如有非Promise项,则此项当做成功

把每一个Promise的结果,集合成数组返回

function allSettled(PromiseArr){
    return new Promise(resolve=>{
        let res = []
        let count = 0
        // 定义一个处理结果的函数
        const addRes = (status,value,index)=>{
            // 作为处理对象的函数
            let obj = {}
            if(status === 'fulfilled') obj = {status,value}
            else obj = {status,reason:value}
            res[index] = obj
            count++
            // 当全部处理完成就返回结果
            if(count === PromiseArr.length) resolve(res)
        }
        // 遍历待处理的数组依次添加到结果中
        PromiseArr.forEach((item,index)=>{
            if(item instanceof Promise){
                item.then(res=>{
                    addRes('fulfilled',res,index)
                },err=>{
                    addRes('rejected',err,index)
                })
            }else{
                addRes('fulfilled',item,index)
            }
        })
    })
}
// polyfill 处理 方法二
function allSettledPolyfill(PromiseArr){
    const success = value=>({ status:'fulfilled',value})
    const reason = reason=>({ status:'rejected',reason})
    const convertedPromise = PromiseArr.map(p=>Promise.resolve(p).then(success,reason))
    return Promise.all(convertedPromise)
}

4、Promise.any

Promise.any

只要其中的一个 promise 成功,就返回那个已经成功的 promise 。

如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和AggregateError类型的实例,

它是 Error 的一个子类,用于把单一的错误集合在一起。

function any(PromiseArr){
    return new Promise((resolve,reject)=>{
        let failArr = []
        const addFail = (index,fail)=>{
            failArr[index] = fail
            if(failArr.length === PromiseArr.length) reject(fail)
        }
        PromiseArr.forEach((item,index)=>{
            if(item instanceof Promise){
                item.then(res=>{resolve(res)},err=>addFail(index,item))
            }else{
                queueMicrotask(()=>{resolve(item)})
            }
        })
    })
}

5、Promise.finally

Promise.finally Promise中无论是否成功,都会执行

Promise.prototype.myfinally = function(callback){
    // 自主想法实现finally同步,与原本一样即没有进入微任务,而当同步任务执行
    callback()
    return this
}
// 文章写法
    // return this.then(res=>{
    //   callback()
    //   return res
    // })

Async、await 的实现

使用ES6中的generator生成器,及yield关键字传参调用实现

// 模拟异步任务
function fn(num) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(num * 2)
        }, 1000)
    })
}
// generator 生成器函数,yield关键字,传参调用
function* gen() {
    const num1 = yield fn(1)
    // console.log((num1));
    const num2 = yield fn(num1)
    // console.log((num2));
    const num3 = yield fn(num2)
    // console.log((num3));
    return num3
}

function generatorToAsync(generatorFn) {
    return function () {
        const gen = generatorFn.apply(this, arguments) // gen有可能传参

        // 返回一个Promise
        return new Promise((resolve, reject) => {

            function go(key, arg) {
                let res
                try {
                    res = gen[key](arg) // 这里有可能会执行返回reject状态的Promise
                } catch (error) {
                    return reject(error) // 报错的话会走catch,直接reject
                }

                // 解构获得value和done
                const { value, done } = res
                if (done) {
                    // 如果done为true,说明走完了,进行resolve(value)
                    return resolve(value)
                } else {
                    // 如果done为false,说明没走完,还得继续走

                    // value有可能是:常量,Promise,Promise有可能是成功或者失败
                    return Promise.resolve(value).then(val => go('next', val), err => go('throw', err))
                }
            }

            go("next") // 第一次执行
        })
    }
}


测试代码:

// 测试代码
const p1 = generatorToAsync(gen)
p1().then(res => {
    console.log(res);
},err=>{
    console.log(err);
})

// async await 写法
async function asyncFn() {
    const num1 = await fn(1)
    // console.log(num1) // 2
    const num2 = await fn(num1)
    // console.log(num2) // 4
    const num3 = await fn(num2)
    // console.log(num3) // 8
    return num3
}
const asyncRes = asyncFn()
console.log(asyncRes) // Promise
asyncRes.then(res => console.log(res)) // 8

在外部调用next方法,会产生回调地狱

// 不用generatorToAsync处理函数的原生yield写法
// 存在回调地狱,所以建议使用generatorToAsync函数在内部调用next
const go = gen()
const {value} = go.next()
value.then(res=>{
    console.log(res);
    const {value} = go.next(res)
    value.then(res=>{
        console.log(res);
        const {value} = go.next(res)
        value.then(res=>{
            console.log(res);
        })
    })
})
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值