• 这次彻底学会面试必考的 Promise 手写题
  • 发布于 2个月前
  • 136 热度
    0 评论
前言
开始手写 Promise 相关必考面试函数之前我会讲一些一些前置小编程知识(常被开发者忽视,避免死记硬背!如果都了解可以跳过这一部分)。

函数签名
手写一个函数时,第一步应该考虑的是函数签名!什么是函数签名?
函数功能:函数的单一职责是什么,先确定好。
函数名称:符合单一职责的函数名称,让使用者通过名称可以清楚知道函数作用,不用关心函数内部实现
函数参数: 函数参数定义,与名称相同,语义明确

函数返回值: 注意是否有返回值,以及明确内容


这里我更推荐 TypeScript, TypeScript 对参数类型,返回值类型等约束的比较到位。

这四点是你在写一个函数时应该重点考虑的内容,一个优秀的函数是不需要使用者关心函数内部实现的。你可以看看 MDN 中函数的实现,举个例子:Array.prototype.findIndex 这种语义就很明确,使用者不需要关心内部实现。

好了接下来回到本文主题,手写大厂面试常考的面试题 Promise.all 和 Promise.race。在实现这两个函数时候不要忘记我前面提到的函数签名知识点。
Promise.all
Promise.all 函数签名
1.Promise.all 的功能介绍
Promise.all 是一个 JavaScript Promise 方法,它接收一个可迭代对象(如数组或类数组对象)作为参数,并返回一个新的 Promise 对象。

Promise.all 的作用是在给定的可迭代对象中的所有 Promise 都完成时,返回一个包含所有 Promise 结果的新 Promise 对象。如果可迭代对象中的任何一个 Promise 被拒绝(rejected),则返回的 Promise 对象会立即被拒绝,并且会带有被拒绝的 Promise 的原因。

简而言之,Promise.all 可以将多个 Promise 并行执行,并在所有 Promise 都完成时返回一个包含所有结果的 Promise 对象。

2.函数名:手写现有函数 仍然使用 all 函数
3.参数:一个可迭代对象

4.返回值:返回的是一个 promise 对象


特殊说明点:
Promise.all 接收的是一个迭代器,不是普通数组。网上很多文章是有问题的
Promise.all 接收的迭代器顺序和返回出去的结果顺序应该是一致的
Promise.all 返回的是一个 promise 对象

Promise.all 只传递的迭代器,且所有都是 fulled 状态,才会返回完成


开始编码阶段
阶段一:Promise.all 一定返回返回一个Promise对象
Promise.myAll = (promiseIterator)=>{
    let res,rej;
    const p = new Promise((resolve,reject)=>{
        res = resolve;
        rej = reject;
    })
    return p;
}
阶段二:临界场景 如果传入一个空的迭代器,返回什么?
这里特殊说一下,因为原生 Promise.all 函数中接受的是一个迭代器对象,并非数组。所以使用 for of 遍历记录 count 数量。看网上很多手写 Promise.all 文章没有考虑到这点。
Promise.myAll = (promiseIterator)=>{
    let res,rej;
    const p = new Promise((resolve,reject)=>{
        res = resolve;
        rej = reject;
    })
    const result = [];
    let count = 0;
    for (const iterator of promiseIterator) {
        count ++;
    }
    if(count === 0){
        res(result);
    }
    return p;
}
阶段三:for 循环中执行每一个 promise
这里执行每一个 promise,使用的 Promise.resolve
Promise.myAll = (promiseIterator)=>{
    let res,rej;
    const p = new Promise((resolve,reject)=>{
        res = resolve;
        rej = reject;
    })
    const result = [];
    let count = 0;
    for (const iterator of promiseIterator) {
        count ++;
        Promise.resolve(iterator).then((r)=>{
            
        },(reason)=>{
           rej(reason)
        })
    }
    if(count === 0){
        res(result);
    }
    return p;
}
记录完成的promise,如果全部完成将最终结果resolve
这里有注意点:
Promise.all 参数传入的可迭代器对象,经过 Promise.all 执行完成后,最终返回的结果要和入参时的顺序相同,所以需要有一个遍历记录 promise 执行的索引,确保放入到 result 数组中顺序相同,返回的顺序也相同。
需要有变量记录全部 fullFilled 完成的 promise 。全部完成时 resolve(result);如果 fullFilled 状态失败 也要返回 reject(result);
Promise.myAll = (promiseIterator)=>{
    let res,rej;
    const p = new Promise((resolve,reject)=>{
        res = resolve;
        rej = reject;
    })
    const result = [];
    let count = 0;
    let fulledCount = 0;
    for (const iterator of promiseIterator) {
        let i = count;
        count ++;
        Promise.resolve(iterator).then((r)=>{
            result[i] = r;
            fulledCount ++;
            if(fulledCount === count){
                res(result)
            }
        },(reason)=>{
           rej(reason)
        })
    }
    if(count === 0){
        res(result);
    }
    return p;
}
Promise.all 完整代码
Promise.myAll = (promiseIterator)=>{
    let res,rej;
    const p = new Promise((resolve,reject)=>{
        res = resolve;
        rej = reject;
    })
    const result = [];
    let count = 0;
    let fulledCount = 0;
    for (const iterator of promiseIterator) {
        let i = count;
        count ++;
        Promise.resolve(iterator).then((r)=>{
            result[i] = r;
            fulledCount ++;
            if(fulledCount === count){
                res(result)
            }
        },(reason)=>{
           rej(reason)
        })
    }
    if(count === 0){
        res(result);
    }
    return p;
}
测试验证
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);

Promise.all([promise1, promise2, promise3])
  .then((results) => {
    console.log(results); // 输出: [1, 2, 3]
  })
  .catch((error) => {
    console.error(error);
  });
Promise.race
1.Promise.race 函数签名
Promise.race 的功能介绍
Promise.race 的作用是在给定的可迭代对象中的任何一个 Promise 完成(无论是解决还是拒绝)时,返回一个新的 Promise 对象。返回的 Promise 对象将具有第一个完成的 Promise 的结果或原因。

划重点:无论解决还是拒绝 简而言之,Promise.race 可以将多个 Promise 并行执行,并返回一个新的 Promise 对象,该对象将具有第一个完成的 Promise 的结果或原因。

2.函数名:手写现有函数 仍然使用 race 函数
3.参数:一个可迭代对象 iterator
4.返回值:返回的是一个 promise 对象 特殊说明点:

Promise.race 无论解决还是拒绝,只要第一个完成立即返回


编码实现
返回一个promise对象
Promise.race = (promiseIterator)=>{
    let res,rej
    const p = new Promise((resolve,reject)=>{
        res = resolve;
        rej = reject;
    })
    return p;
}
竞赛,不管任何一个先完成都要立即返回
Promise.race = (promiseIterator)=>{
    let res,rej
    const p = new Promise((resolve,reject)=>{
        res = resolve;
        rej = reject;
    })
    for (const prom of promiseIterator) {
        Promise.resolve(prom).then(value=>{
            res(value)
        },(reason)=>{
            rej(reason)
        })
    }
    return p;
}
测试验证
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('Promise 1 resolved');
    }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject(new Error('Promise 2 rejected'));
    }, 2000);
});

Promise.race([promise1, promise2])
.then((result) => {
    console.log(result); // 输出: Promise 1 resolved
})
.catch((error) => {
    console.error(error); // 不会执行,因为 promise1 先完成
});
Promise.any 和 Promise.allSettled
Promise.any
作用:从多个 Promise 中返回第一个成功(resolve)的 Promise 结果
使用场景:当你需要多个异步操作中的任意一个成功时使用,比如加载多个资源只需一个成功即可继续。
Prmise.allSettled

作用:等待所有 promise 完成,无论成功或失败,并返回一个包含所有 promise 结果(成功或失败的详细信息)的数组
使用场景:当你需要执行多个并行操作并且你需要知道每个操作的成功或在失败详细情况时使用,适用于结果汇总且并不依赖单个任务的成功与否。
这两个函数具体实现就不写了,只说明一下作用和使用场景,留个作业,小伙伴们可以实现一下评论区回复哦! 

创作不易,感谢大家点赞,转发!
用户评论