并发限制
- 实现并发控制关键,limit 内循环发出,有任务完成后从 doingNum 中减去,递归调用
简版原理
js
function get(i) {
console.log('In ', i)
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(i * 1000)
console.log('Out', i, 'Out')
}, i * 1000)
})
}
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let count = 0
function run() {
if (count < 3 && list.length) {
count += 1
get(list.shift()).then(() => {
count -= 1
run()
})
}
}
for (let i = 0; i < 3; i++) {
run()
}
调度器实现
思路:某一任务完成后递归调用 优化点:finally
js
class Scheduler {
list = []
limit = 2
doingNum = 0
// 传入待执行的 Promise
add(p) {
this.list.push(p)
}
start() {
for(let i = 0; i < this.limit; i++) {
this.runNext()
}
}
runNext() {
if (this.doingNum < this.limit && this.list.length) {
this.doingNum += 1
this.list.shift()().then(() => {
this.doingNum -= 1
this.runNext()
})
}
}
}
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
let scheduler = new Scheduler()
const addTask = (time, order) => {
scheduler.add(() => sleep(time).then(() => console.log(order)))
}
// 异步任务模拟
addTask(1000, 1)
addTask(500, 2)
addTask(300, 3)
addTask(400, 4)
scheduler.start() // 2, 3, 1, 4
race 版
头条前端面试题之 Promise 并发数限制_哔哩哔哩 (゜-゜)つロ 干杯~-bilibilisindresorhus/p-limit: Run multiple promise-returning & async functions with limited concurrencysindresorhus/promise-fun: Promise packages, patterns, chat, and tutorials
串行加并行
js
// [1,[2,3],4,[5,6,7],8]
// 串行 shift then
// 并行 limit 完成后恢复串行
// 全部完成 done
class Scheduler {
constructor(tasks, limit) {
this.quene = tasks
this.limit = limit
this.doingNum = 0
this.index = 0
}
start() {
this.next()
}
startP(tasks) {
this.doingNum = 0
for(let i = 0; i < limit; i++) {
nextP(tasks)
}
}
nextP(tasks) {
if (tasks.length <= 0) {
next()
return
}
if (this.doingNum < this.limit) {
this.doingNum++
Promise.resolve(tasks.shift()).then(() => {
this.doingNum--
this.nextP(tasks)
})
}
}
next() {
if (this.index >= this.length) {
console.log('done')
return
}
const task = this.tasks[this.index]
if (Array.isArray(task)) {
startP(task)
return
}
Promise.resolve(task).then(() => {
this.index++
this.next()
})
}