一起养成写作习惯!这是我参与「日新计划 4 月更文应战」的第3天,点击检查活动概况。
前因
最近周末闲着无事,在上刷着沸点,刷着文章,忽然看到这么一个面试题
完结一个办法multiRequestLimitNum(reqArr, limitNum)
,这个办法有以下功用
- 能够并发发恳求
- 但是并发的恳求数有限制,不能超过limitNum。
- 并发的恳求每成功一个,就能够从reqArr中取一个去补上,满意最大并发数limitNum。
- 最后回来值需求依照reqArr的次序回来。
分析
一开始看到并发发恳求,就会想到Promise.all
,它能够完结恳求的并发,但是它并不能操控最大并发数。
而且它要成功一个,就要补上一个。现在Promise.all
应该是做不到的,只能另辟蹊径。
现有的api都无法满意,那只能手写办法来完结。
第一步
咱们先判别当前reqArr的长度是否大于最大并发数。假如大于则无需处理,假如小于则最大并发数是reqArr的长度。
然后遍历,我这儿运用while循环,界说个索引i
等于0,然后i++
,每次都履行恳求函数,直到i等于最大并发数。
这样模仿并发。
第二步
咱们的i++是在恳求函数里面履行的,把当前索引赋值cur
变量,履行reqArr对应i索引的函数,
把回来值赋值给一开始界说的reqArr长度的数组resArr。
但是履行函数是异步的,这时分i
是已经变化了,能够经过前面赋值的cur
变量来把回来值放到resArr对应的方位。
这姿态能够保证回来的次序是依照reqArr的次序。
第三步
假如此刻 i
还不等于reqArr的长度,则递归调用恳求函数,这样就满意成功一个恳求,就补上一个恳求。
直到i等于reqArr的长度的时分,则代表reqArr的恳求已经完结,把数组resArr resolve回来即可。
代码如下:
function multiRequestLimitNum (reqArr, limitNum) {
const reqLen = reqArr.length
const resArr = new Array(reqLen)
let i = 0
return new Promise(async (resolve, reject) => {
const maxNum = reqLen >= limitNum ? limitNum : reqLen
while (i < maxNum) {
reqFn()
}
async function reqFn () {
const cur = i++
const fn = reqArr[cur]
const data = await fn().catch((err) => { return err })
resArr[cur] = data
if (i === reqArr.length) resolve(resArr)
else reqFn()
}
})
}
咱们用上面的代码来验证一下,用setTimeout来模仿发出的恳求
function req (res, delay) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(res)
}, delay)
})
}
multiRequestLimitNum([
req.bind(null, 1, 1000),
req.bind(null, 2, 500),
req.bind(null, 3, 2000),
req.bind(null, 4, 100)],
2)
经过图片能够看到,咱们传入函数的延时都是不一样的,但是打印出来的结果是依照传入的次序打印的。
而且并发的恳求是成功一个,才会取下个恳求去恳求。
我们能够试试。
我们假如有其它办法欢迎谈论,一起交流。