-
Notifications
You must be signed in to change notification settings - Fork 8
Open
Labels
Description
如何处理循环的异步操作
示例代码中tasks为异步操作队列,代码忽略任务执行结果的记录和错误处理
并行异步操作
Promise.all
Promise.all(tasks.map(task => task()))
.then(() => doSomethingAfter())
// 也可结合 async/await使用
;(async () => {
await Promise.all(tasks.map(task => task()))
doSomethingAfter()
})()检测完成个数
let finishedNum = 0
let taskNum = tasks.length
tasks.forEach((task, i) => {
task(() => {
// 完成任务个数记录
finishedNum++
// 检测是否全部完成
if (finishedNum === taskNum) {
doSomethingAfter()
}
})
})串行异步操作
promise.then
使用promise.then循环拼接任务,最后拼接完成之后的操作
let taskPromise = Promise.resolve()
tasks.forEach((task, i) => {
taskPromise = taskPromise.then(() => task())
})
// 完成所有任务后
taskPromise.then(() => doSomethingAfter())一个比较抖机灵的写法,通过Array.prototype.reduce实现,原理和上例相同:
const taskPromise = tasks
.reduce((promise, task) => {
promise = promise.then(() => task)
return promise
}, Promise.resolve())
.then(() => doSomethingAfter())递归调用
const runTasksSerially = tasks => {
if (tasks.length <= 0) {
return doSomethingAfter()
}
const taskToRun = tasks.shift() // 取出首个任务
// 执行完成后,回调内将剩余任务传入runTasksSerially执行,实现串行
taskToRun(() => runTasksSerially(tasks))
}
runTasksSerially(tasks)控制并发数
即将任务按并发数分组,组内并行执行,组间串行执行。
// Promise.all并行执行
const runTasksConcurrently = tasks => Promise.all(tasks.map(task => task()))
// Promise.then串行执行
const runTasksSerially = tasks => tasks.reduce((p, task) => p.then(() => task()), Promise.resolve())
const runTasks = (tasks, concurrency) => {
// 分割任务组,组个数为 Math.ceil(tasks.length / concurrency),组内任务个数为concurrency
const dividedTasks = Array.from({ length: Math.ceil(tasks.length / concurrency) }, (_, i) => {
return tasks.slice(i * concurrency, i * concurrency + concurrency)
})
// 生成组内并行执行,组间串行执行的任务组
const serialTasks = dividedTasks.map(concurrentTasks => {
return () => runTasksConcurrently(concurrentTasks)
})
// 串行执行生成的任务组(注:单个组内的各个任务并行执行)
return runTasksSerially(serialTasks)
}
runTasks(tasks, 3).then(() => doSomethingAfter())