JavaScript 作为单线程语言,通过事件循环和异步机制实现并发。文章介绍并发与并行区别,讲解 Promise 相关 API 及如何使用 p-limit 库或手写代码控制并发数,给出批量上传等实战示例,并总结最佳实践。
JS 是单线程模型,主要通过事件循环和异步机制实现 “并发”。
JavaScript 运行在单线程环境(如浏览器主线程),但可以通过异步任务(如 setTimeout、Promise、fetch)实现任务切换。
如果不加控制,可能导致瞬时请求数过多,服务器压力大或被限流。
Promise.all:并发执行所有任务,全部成功才 resolve。Promise.race:并发执行,最先完成的任务 resolve。Promise.allSettled:并发执行,所有任务完成后返回每个任务的结果。注意:这些 API 本身不会限制并发数。
import pLimit from 'p-limit';
const limit = pLimit(3); // 最多3个并发
const tasks = urls.map((url) => limit(() => fetch(url)));
const results = await Promise.all(tasks);
class Task {
limit = 0;
executing = 0;
queue = [];
constructor(limit = 4) {
this.limit = limit;
}
run() {
while (this.executing < this.limit && this.queue.length > 0) {
const taskFn = this.queue.shift();
this.executing++;
taskFn().finally(() => {
this.executing--;
})
}
}
add(taskFn) {
this.queue.push(taskFn)
this.run()
}
}
const createRequest(delay, name) {
return () => {
return new Promise((resolve) => {
console.time(name)
setTimeout(() => {
resolve()
console.timeEnd(name)
}, delay)
})
}
}
const task = new Task(2)
const r1 = createRequest(1000, 'r1')
const r2 = createRequest(2000, 'r2')
const r3 = createRequest(3000, 'r3')
const r4 = createRequest(4000, 'r4')
task.add(r1)
task.add(r2)
task.add(r3)
task.add(r4)
task.run()
比如你要批量上传 100 张图片,但每次只允许 5 个并发:
import pLimit from 'p-limit';
const limit = pLimit(5);
const uploadTasks = files.map((file) => limit(() => uploadFile(file)));
await Promise.all(uploadTasks);
参考资料: