这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战
这个系列也没啥花头,就是来整平时面试的一些手写函数,考这些简单实现的好处是能看出基本编码水平,且占用时间不长,更全面地看出你的代码实力如何。一般不会出有很多边界条件的问题,那样面试时间不够用,考察不全面。
平时被考到的 api 如果不知道或不清楚,直接问面试官就行, api 怎么用这些 Google 下谁都能马上了解的知识也看不出水平。关键是在实现过程,和你的编码状态、习惯、思路清晰程度等。
注意是简单实现,不是完整实现,重要的是概念清晰和实现思路清晰,建议
先解释清楚概念
=>写用例
=>写伪代码
=>再实现具体功能
,再优化
,一步步来。
30. Promise.race
分析
我们之前提到了一个Promise的 api Promise.all
, 现在我们实现下 Promise.race()
了解下Promise.race()
的用处
Promise.race(iterable)
方法返回一个 promise,一旦迭代器中的某个 promise解决或拒绝
,返回的 promise 就会解决或拒绝。
语法
Promise.race(iterable);
参数
- iterable
可迭代对象,类似Array
, 跟 Promise.all
一样
返回值
- 一个待定的 Promise
只要给定的迭代中的一个promise解决或拒绝,就采用第一个promise的值作为它的值,从而异步地解析或拒绝(一旦堆栈为空)。
描述
-
race
函数返回一个Promise
,它将与第一个传递的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个
。 -
如果传的迭代是
空
的,则返回的 promise 将永远等待。 -
如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race 将解析为迭代中
找到的第一个值
。
看个例子:
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(reject, 300, 'three');
});
Promise.race([promise1, promise2, promise3]).then((value) => {
console.log(value);
});
// two
// 打印 two 因为 promise2 最快执行完毕
Promise.race([promise1, promise3]).then((value) => {
// 未被调用
console.log(value);
}).catch(reason => {
console.log(reason, 'is reject');
});
// three is reject
// 最快的是拒绝的 promise3, 所以走了 catch
在实现这个方法之前,建议看下这篇 手写Promise.all
手写实现
const myPromiseRace = (iterableArr) => {
// 返回一个 Promise
return new Promise((resolve, reject) => {
if (!Array.isArray(iterableArr)) {
return reject(new Error('params is not an iterator Array'))
}
// 开始遍历每个迭代元素
for (item of iterableArr) {
Promise.resolve(item).then((res) => {
// promise 数组只要有任何一个 promise状态变更,就返回
resolve(res)
}).catch(e => {
reject(e)
})
}
})
}
// 同样用我们的测试用例来实验下
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(reject, 300, 'three');
});
myPromiseRace([promise1, promise2, promise3]).then((value) => {
console.log(value);
});
// two
myPromiseRace([promise1, promise3]).then((value) => {
console.log(value);
}).catch(reason => {
console.log(reason, 'is reject');
});
// three is reject
没有问题,之后我们会利用这个 Promise.race
来限制异步的并发数量。
31. Promise.allSettled
分析
我们在这篇中介绍了 Promise.allSettled
简单来说 Promise.allSettled()
方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。
我们在之前的一篇文章中已经介绍过,当我们使用 Promise.all()
执行过个 promise
时,只要其中任何一个promise
失败都会执行 reject
,并且 reject
的是第一个抛出的错误信息,只有所有的 promise
都 resolve
时才会调用 .then
中的成功回调
我们直接看实现, 很像 Promise.all
手写实现
先写测试用例, 建立 4 个 promise, 第四个是失败的。
// 先建立一个工厂函数, 入参是名字和异步时间
const promiseFactory = (name, wait, isFail = false) => {
return new Promise((resolve, reject) => {
// 异步任务(用 setTimeout 模拟)
setTimeout(() => {
if (!isFail) {
resolve(`我是 ${name},我需要 ${wait} ms, 执行成功`)
} else {
reject(`我是 ${name},我需要 ${wait} ms, 执行失败`)
}
}, wait)
})
}
let pro1 = promiseFactory('第一个异步任务', 3000)
let pro2 = promiseFactory('第二个异步任务', 1000)
let pro3 = promiseFactory('第三个异步任务', 2000)
let pro4 = promiseFactory('第四个异步任务', 1500, true)
然后实现
const myPromiseAllSettled = (iterableArr) => {
return new Promise((resolve, reject) => {
if (!Array.isArray(iterableArr)) {
return reject(new Error('params is not an iterator Array'))
}
let res = [], count = 0
for (let i = 0; i < iterableArr.length; i++) {
Promise.resolve(iterableArr[i]).then(value => {
res[i] = {status: "fulfilled", value: value}
}).catch(err => {
res[i] = {status: "rejected", reason: err}
}).finally(() => {
// 每次都计数,直到全部执行完,返回结果
count++
if (count === iterableArr.length) {
resolve(res)
}
})
}
})
}
myPromiseAllSettled([pro2, pro1, pro3, pro4]).then(res => {
console.log(res)
}, err => {
console.log(err)
})
// 3秒后打印结果, 不管成功失败,都会返回
// [
// {status: "fulfilled", value: "我是 第二个异步任务,我需要 1000 ms, 执行成功"},
// {status: "fulfilled", value: "我是 第一个异步任务,我需要 3000 ms, 执行成功"},
// {status: "fulfilled", value: "我是 第三个异步任务,我需要 2000 ms, 执行成功"},
// {status: "rejected", reason: "我是 第四个异步任务,我需要 1500 ms, 执行失败"}
// ]
这样也就成功实现了。
另外向大家着重推荐下另一个系列的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列 记得点赞哈
今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 点击此处交个朋友
Or 搜索我的微信号infinity_9368
,可以聊天说地
加我暗号 "天王盖地虎" 下一句的英文
,验证消息请发给我
presious tower shock the rever monster
,我看到就通过,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧