第 153 题:实现一个批量请求函数 multiRequest(urls, maxNum)
要求如下:
- 要求最大并发数 maxNum
- 每当有一个请求返回,就留下一个空位,可以增加新的请求
- 所有请求完成后,结果按照 urls 里面的顺序依次打出
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
要求如下:
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(55)
开始0 2020/5/18 上午11:34:37
开始1 2020/5/18 上午11:34:37
开始2 2020/5/18 上午11:34:37
开始3 2020/5/18 上午11:34:37
开始4 2020/5/18 上午11:34:37
结束4 2020/5/18 上午11:34:37
失败 4
结束0 2020/5/18 上午11:34:37
结束3 2020/5/18 上午11:34:37
结束1 2020/5/18 上午11:34:37
结束2 2020/5/18 上午11:34:37
@SupermanWY
借鉴了你的写法,但是有个地方有bug,while循环那里,如果输入的urls的长度小于maxNun,就会一直执行了,所以需要限制一下
我第一感觉是:他让我写个promise.all
const apiPath = 'http://localhost:3000/';
let urlList = [
${apiPath}test1
,${apiPath}test2
,${apiPath}test3
,${apiPath}test4
,${apiPath}test5
];function request(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.open('get', url, true); //这里第三个参数不能为false,会变成同步
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200 || xhr.status == 304) {
resolve(xhr.responseText)
}
}
}
xhr.send()
})
}
后台koa启个node服务 大概是
router.get('/test1', async (ctx) => {
let res = await delay(1000)
ctx.type = 'application/json';
ctx.body = {
status: 200,
msg: 'test1 OK'
}
});
router.get('/test2', async (ctx) => {
let res = await delay(2000)
ctx.type = 'application/json';
ctx.body = {
status: 200,
msg: 'test2 OK'
}
});
router.get('/test3', async (ctx) => {
let res = await delay(3000)
ctx.type = 'application/json';
ctx.body = {
status: 200,
msg: 'test3 OK'
}
});
router.get('/test4', async (ctx) => {
let res = await delay(4000)
ctx.type = 'application/json';
ctx.body = {
status: 200,
msg: 'test4 OK'
}
});
router.get('/test5', async (ctx) => {
let res = await delay(5000)
ctx.type = 'application/json';
ctx.body = {
status: 200,
msg: 'test5 OK'
}
});
function multiRequest(urls, maxNum = 8) {
let currentUrls;
let curIdx = 0
let currentResList = []
function next() {
currentUrls = urls.slice(curIdx,curIdx+maxNum)
return new Promise((resolve) => {
for (let item of currentUrls) {
request(item).then(res => {
currentResList.push(res)
// console.error(curIdx,currentResList,currentUrls)
if ( (currentResList.length)-curIdx == currentUrls.length ) {
curIdx = curIdx + currentUrls.length
if(curIdx < urls.length ){
next().then(resolve)
}else{
resolve(currentResList)
}
}
})
}
})
}
return new Promise(resolve=>{
next().then(res => {
resolve(res)
})
})
}
multiRequest(urlList, 2).then(res=>{
console.error(res,'rsss')
})
大概这样
@sheepshine 题目中的条件2、每当有一个请求返回,就留下一个空位,可以增加新的请求, 直接用promise.all应该做不到吧?
const promise = new Promise(r => resolve = r);
这行看不懂。。。。好尴尬
递归调用来实现,这个想法是,最初您发送的请求数量上限为允许的最大值,并且这些请求中的每一个都应该在完成时继续递归发送,通过传入的索引来确定了urls 里面具体是那个URL,保证最后输出的顺序不会乱,而是依次输出;
看了下题目,不知道我这种实现对不对?没有验证过:
实现
测试
感觉就是一个promiseAll的变种
大佬们,我这样写可行?
用generator写一个
multiRequest 实现
测试代码
面试被问到过,写一写:
比如maxNum设置为2时,第三个请求进来还是先执行了,是不是不对
this.taskList.push(resolve) 请问这里为什么添加resolve
直接用分頁的概念做,最後用 flat 把結果壓平
测试结果,图片不知道为啥不显示
开始0 2020/5/18 上午11:28:47
开始1 2020/5/18 上午11:28:47
开始2 2020/5/18 上午11:28:47
开始3 2020/5/18 上午11:28:47
开始4 2020/5/18 上午11:28:47
结束0 2020/5/18 上午11:28:47
开始5 2020/5/18 上午11:28:47
结束5 2020/5/18 上午11:28:51
开始6 2020/5/18 上午11:28:51
结束4 2020/5/18 上午11:28:53
开始7 2020/5/18 上午11:28:53
结束7 2020/5/18 上午11:28:53
开始8 2020/5/18 上午11:28:53
结束1 2020/5/18 上午11:28:54
开始9 2020/5/18 上午11:28:54
结束3 2020/5/18 上午11:28:54
结束2 2020/5/18 上午11:28:55
结束9 2020/5/18 上午11:28:55
结束6 2020/5/18 上午11:28:56
结束8 2020/5/18 上午11:29:01
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
目前设定的是,当执行过程中某个 promise 返回 reject 则停止后续的 promise 执行。
后续可以加上,abort 请求。可以是一个回调,失败时候把 executing 传递过去。回调去执行一些操作。
说白了,就是实现一个限制并发的 Promise.all
这个不行吧,请求不是按顺序返回的,切要并发请求吧
res是请求链接,res.then鞋油问题吧
class Scheduler {
constructor(count) {
this.count = count;
this.task = [];
this.executing = 0;
}
add(promiseCreator) {
this.task.push(() => promiseCreator());
this.executing < this.count && this.runTask();
}
runTask() {
if (this.task.length === 0) return;
this.executing++
this.task.splice(0, 1)0.then(() => {
this.executing--
this.runTask();
})
}
}
const timeout = (time) => new Promise((resolve, reject) => {
setTimeout(resolve, time);
})
function multiRequest(urls = [], maxNum = 1) {
let scheduler = new Scheduler(maxNum);
const addTask = (time, order) => {
scheduler.add(() => timeout(time).then(() => console.log(order)))
}
for (let i = 0; i < urls.length; i++) {
addTask(1000, urls[i]);
}
}
如果网络太好,建议将Network throttling 调成Fast 3G。
借鉴了一些题解的实现,用例跑通了,有问题或者可优化的话请各位大佬指正。
解题的关键是:队列和递归
代码如下
通过count计数的形式,判断接口是否全部完成