- Published on
js代码分享:异步任务并发限制器
- Authors
- Name
- 国Wei
- @ygweric
最近写爬虫,批量爬取网页,但又要限制下并发了,避免太占资源。
自己想了想js代码怎么写,发现还挺复杂的,后来索性咨询了ChatGPT,(ChatGPT的代码比通义的好很多),上代码。
代码如下,测试通过,但是代码我看不懂!!!
export async function runWithConcurrencyLimit(tasks, limit) {
const result = [];
const executing = [];
for (const task of tasks) {
const p = Promise.resolve().then(() => task()); // 包装为 promise 执行任务
result.push(p);
if (limit <= tasks.length) { // 默认边界检查,可以忽略
const e = p.then(() => executing.splice(executing.indexOf(e), 1)); // 从队列中移除已完成任务 ---------- 这一行代码看不懂,e是谁??
executing.push(e);
if (executing.length >= limit) { // 超过limit了
// eslint-disable-next-line no-await-in-loop
await Promise.race(executing); // 等待最先完成的任务
}
}
}
return Promise.all(result);
}
闲下来了,好好研究一番,看的更懵逼了。索性用通义灵码解释一番,竟然发现灵码还能生成流程图,帮助我理解,我觉得自己越来越菜了,动手能力越来越差。
下面着重理解下 executing.splice(executing.indexOf(e), 1))
这个代码
executing.indexOf(e)
const e = p.then(() => executing.splice(executing.indexOf(e), 1)); // 从队列中移除已完成任务 ---------- 这一行代码看不懂,e是谁??
问
上面代码中的“const e = p.then(() => executing.splice(executing.indexOf(e), 1));”不理解,e是返回的结果,为什么还可以用在indexOf中
答:
这行代码确实有些 tricky,让我们详细解释一下:
const e = p.then(() => executing.splice(executing.indexOf(e), 1));
p
是一个 Promise:p
是通过Promise.resolve().then(() => task())
创建的,表示一个异步任务的执行。p.then(...)
:当p
这个 Promise 完成时(即任务执行完毕),会执行then
方法中的回调函数。const e
:这里e
是p.then(...)
返回的新 Promise。这个新 Promise 在p
完成后会被解析。executing.splice(executing.indexOf(e), 1)
:在p
完成时,从executing
数组中移除e
。
关键点
e
的作用:e
是一个 Promise,它表示p
完成后的状态。当p
完成时,e
会被解析,并且executing
数组中的e
会被移除。executing.indexOf(e)
:在p
完成时,e
已经存在于executing
数组中,因此executing.indexOf(e)
可以找到e
的索引位置。
总结
上面代码用了js的闭包功能,闭包是指一个函数能够访问其外部作用域中变量的能力。即使外部函数已经执行完毕,内部函数仍然可以访问这些变量。 又超出我的想象了。
代码流程图
关于我
国 wei (Eric) Github