前言
分享一首bgm进入正题咯:普普通通
并发请求的处理,说起来也算是一道必问题,网上其实已经有很多答案了各种做法,但自己做个记录,来吧我们直接上题。
请实现如下函数,可以批量请求数据,所有 URL 地址在
urls参数中,同时可以通过max参数控制请求的并发度,当所有请求执行结束后需要执行callback回调函数,请求函数用 fetch 即可(不做请求失败处理)。
司尘:我们普普通通 脑袋空空 题看不懂 望向天空 skr~~~
理理思路
简化问题
面试官:看你脑袋空空,给你简化一下问题吧,我们不管max值你先实现请求完执行callback
function requestData(urls = [], callback = ()=>{}) {
let requestArr = []
for(let i = 0, length = urls.length; i < length; i++) {
// fetch的用法可以直接MDN看一下吼
requestArr.push(fetch(urls[i]))
}
Promise.all(requestArr)).then(() => {
callback();
}).catch(err => {
console.log(err)
})
}
面试官:额,这应该是最粗暴的办法了,那你把max限制加上,然后转换一下思路再看一下怎么完成题目咧,提示一下可以用递归。
机智的读者:哦哦哦,懂了交给我了
具体流程
根据
max值我们建立一个请求的执行数组requestArr(长度上限就为max了)我们将请求的promise一项一项丢入到其中(递归实现),执行完毕就删除掉
requestArr到达上限那么我们等待请求执行,有空位在继续添加
urls添加完毕之后我们将requestArr(这里只需要拿到最后的请求数组是因为,之前请求执行完了才会自己删除自己,所以只需要判定最后的是否都执行完就ok了)进行Promise.all判定执行callback。
上代码
戴好眼镜好好看哦
function requestData(urls = [], max = 1, callback = ()=>{}) {
let requestArr = [],
i = 0;
function toFetch() {
if (i === urls.length) {
// 判定都添加完后返回resolve
return Promise.resolve();
}
// 通过fetch方法创建请求promise
let fetchItem = fetch(urls[i++]);
requestArr.push(fetchItem);
// 给每一项定义一个执行完毕删除自身的微任务
fetchItem.then( () => {requestArr.splice(requestArr.indexOf(fetchItem), 1)});
let result = Promise.resolve();
if (requestArr.length === max) {
// 当执行数组达到上限时我们通过Promise.race方法判定是否有“空位置”
result = Promise.race(requestArr);
}
return result.then(() => toFetch());
}
toFetch().then(() => Promise.all(requestArr)).then(() => {
callback();
})
}
升级一下
其实这个题目他主要思想就是当我们任务队列满了的时候就停住嘛,那我们Promise对象使用.then的话那就只能通过递归去实现了,我们这不是还有await嘛,通过await我们就可以直接在任务队列满掉的时候去判断停住函数。来康代码
async function requestData(urls = [], max = 1, callback = ()=>{}) {
// 这边直接定义一个数组接受所有fetch request
const fetchArr = []
const requestArr = []
for(const item of urls) {
const p = fetch(item)
fetchArr.push(p)
// 如果最大限制比数组小我们才需要走这一步
if(max <= urls.length) {
const e = p.then(() => {
requestArr.splice(requestArr.indexOf(p), 1)
})
requestArr.push(e)
if (requestArr.length >= max) {
await Promise.race(requestArr);
}
}
}
Promise.all(fetchArr)).then(() => {
callback()
})
}
这样我们似乎更巧妙的实现了这个题目。
总结
其实我个人感觉实际应用中这种场景还是比较少的(当然可能也是我见得太少了),但是面试中这也是个高频题了吼,感觉主要还是说考察promise的实际用法。冷风萧瑟,堵在公司,加班不痛,打车才痛,干饭人,冲!!!