一、并发控制基础概念
为什么需要并发控制?
当应用同时处理多个异步操作时(如API请求、文件操作等),无限制的并发会导致:
- 资源耗尽(内存、CPU、网络带宽)
- 服务端拒绝服务(HTTP 429错误)
- 级联故障(雪崩效应)
graph LR
A[大量并发请求] --> B[资源耗尽]
B --> C[服务崩溃]
C --> D[级联故障]
JavaScript并发模型
JavaScript使用事件循环(Event Loop)处理并发,但Node.js和浏览器环境有所不同:
环境 | 并发模型 | 特点 |
---|---|---|
浏览器 | 单线程事件循环 | 每个标签页独立线程 |
Node.js | 多线程+事件循环 | Worker Threads处理CPU密集型任务 |
二、基础并发控制实现
1. Promise.all的并发限制
原生Promise.all无法控制并发数,我们可以实现一个简单的控制版本:
javascript
async function promiseAllLimited(tasks, limit) {
const results = [];
const executing = new Set();
for (const task of tasks) {
// 等待并发数低于限制
if (executing.size >= limit) {
await Promise.race(executing);
}
const p = task().then(res => {
executing.delete(p);
return res;
});
executing.add(p);
results.push(p);
}
return Promise.all(results);
}
// 使用示例
const tasks = [];
for (let i = 0; i < 50; i++) {
tasks.push(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(i);
resolve(i);
}, 1000 * Math.floor(10 * Math.random()));
})
});
}
promiseAllLimited(tasks, 5); // 最大并发5个
2. 基础队列并发控制模型
基础队列并发控制模型,具体的控制队列可以根据自身业务进行扩展,例如添加超时控制,性能监测,任务优先级控制等等
javascript
class TaskQueue {
constructor(concurrency) {
this.concurrency = concurrency;
this.running = 0;
this.queue = [];
}
push(task) {
this.queue.push(task);
this.next();
}
next() {
while (this.running < this.concurrency && this.queue.length) {
const task = this.queue.shift();
task().finally(() => {
this.running--;
this.next();
});
this.running++;
}
}
}
// 使用示例
const queue = new TaskQueue(3);
for (let i = 0; i < 10; i++) {
queue.push(() => new Promise(resolve => {
console.log(`任务 ${i} 开始`);
setTimeout(() => {
console.log(`任务 ${i} 完成`);
resolve();
}, Math.random() * 2000);
}));
}
结语
如果你喜欢本教程,记得点赞+收藏!关注我获取更多JavaScript开发干货。