- 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