- 主要思想就是建立一个中间人channel,一边写入,一边删除,需要理解阻塞和放行,在循环中使用await阻塞向channel中写入数据。
- 为什么必须使用Promise.race(pool) 而不是Promise.all(pool) ?
-
Promise.all要等待所有的promise变为成功状态。假设pool中有10个promise,其中一个非常耗时1min,其他9个只需要1s,使用Promise.all需要等待1min,await才会放行,循环才会继续,白白等待59s。
-
使用Promise.race可以保证,pool中最快的promise改变状态时,await就会放行,继续向pool写入新的promise,通俗来讲,就是1个promise运行结束的同时1个新的promise加入,没有时间间隔
const response = async (id) => {... }
const summarys = new Map();
const retry = new Set();
const asyncRun = async (ids, summarys) => {
const limit = 3;
// limit个异步任务
const pool = new Set();
const retry = new Set();
for (const id of ids){
const task = response(id); //一个请求网页的函数
pool.add(task); // 保存新的异步任务
task.then((s) => {
summarys.set(id, s);
}).catch((err) => {
retry.add(id);
}).finally(() => {
pool.delete(task);
});
if (pool.size < limit) {
continue;
}
try {
await Promise.race(pool);
//阻塞主循环,直到pool中最快的一个promise状态改变
} catch {
continue;
}
}
await Promise.allSettled(pool);
//等待pool余下的promise状态改变,无论状态是否成功
if (retry.size) {
asyncRun(retry, summarys);
} else {
console.log("执行结束");
}
};
asyncRun(ids, summarys);
支持promise在rejected后重新进入任务列表