编程小知识
开始写手写 Promise
相关函数之前我会讲一些前置小编程知识(常被开发者忽视,如果都了解可以跳过这一部分)
大家好,我是芝士,欢迎点此扫码加我微信 Hunyi32 交流,最近创建了一个低代码/前端工程化交流群,欢迎加我微信 Hunyi32 进群一起交流学习,也可关注我的公众号[ 前端界 ] 持续更新优质技术文章
函数签名
手写一个函数时,第一步应该考虑的是函数签名!什么是函数签名?
- 函数功能:函数的单一职责是什么,先确定好。
- 函数名称:符合单一职责的函数名称,让使用者通过名称可以清楚知道函数作用,不用关心函数内部实现
- 函数参数: 函数参数定义,与名称相同,语义明确
- 函数返回值: 注意是否有返回值,以及明确内容
这里我更推荐
TypeScript
,TypeScript
对参数类型,返回值类型等约束的比较到位。
这四点是你在写一个函数时应该重点考虑的内容,一个优秀的函数是不需要使用者关心函数内部实现的。你可以看看 MDN
中函数的实现,举个例子:Array.prototype.findIndex
这种语义就很明确,使用者不需要关心内部实现。
好了接下来回到本文主题,手写大厂面试常考的面试题 Promise.all
和 Promise.race
。在实现这两个函数时候不要忘记我前面提到的函数签名知识点。
Promise.all
Promise.all 函数签名
Promise.all
的功能介绍
Promise.all
是一个 JavaScript Promise
方法,它接收一个可迭代对象(如数组或类数组对象)作为参数,并返回一个新的 Promise
对象。
Promise.all
的作用是在给定的可迭代对象中的所有 Promise
都完成时,返回一个包含所有 Promise
结果的新 Promise
对象。如果可迭代对象中的任何一个 Promise
被拒绝(rejected
),则返回的 Promise
对象会立即被拒绝,并且会带有被拒绝的 Promise
的原因。
简而言之,Promise.all
可以将多个 Promise
并行执行,并在所有 Promise
都完成时返回一个包含所有结果的 Promise
对象。
- 函数名:手写现有函数 仍然使用
all
函数 - 参数:一个可迭代对象
- 返回值:返回的是一个
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
Promise.race 函数签名
Promise.race
的功能介绍
Promise.race
的作用是在给定的可迭代对象中的任何一个 Promise
完成(无论是解决还是拒绝)时,返回一个新的 Promise
对象。返回的 Promise
对象将具有第一个完成的 Promise
的结果或原因。
划重点:无论解决还是拒绝 简而言之,
Promise.race
可以将多个Promise
并行执行,并返回一个新的Promise
对象,该对象将具有第一个完成的Promise
的结果或原因。
- 函数名:手写现有函数 仍然使用
race
函数 - 参数:一个可迭代对象
iterator
- 返回值:返回的是一个
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 先完成
});
大家好,我是芝士,最近创建了一个低代码/前端工程化交流群,欢迎点此扫码加我微信 Hunyi32 交流,也可关注我的公众号[ 前端界 ] 持续更新优质技术文章
Promise.any 和 Promise.allSettled
Promise.any
- 作用:从多个
Promise
中返回第一个成功(resolve
)的Promise
结果 - 使用场景:当你需要多个异步操作中的任意一个成功时使用,比如加载多个资源只需一个成功即可继续。
Prmise.allSettled
- 作用:等待所有
promise
完成,无论成功或失败,并返回一个包含所有promise
结果(成功或失败的详细信息)的数组 - 使用场景:当你需要执行多个并行操作并且你需要知道每个操作的成功或在失败详细情况时使用,适用于结果汇总且并不依赖单个任务的成功与否。
这两个函数具体实现就不写了,只说明一下作用和使用场景,留个作业,小伙伴们可以实现一下评论区回复哦! 创作不易,感谢大家点赞,转发!