1. 完整代码
import React, { useEffect, useRef } from 'react';
import { useDebounceFn } from "ahooks";
// 队列任务类型
interface QueueTask {
id: number | string;
execute: () => PromiseLike<any>;
}
// 异步队列执行方法
function useSyncQueue(params:any) {
const { limit = 3 } = params||{};
const queue = useRef<QueueTask[]>([]);
// 任务执行完成后的回调函数
let overCallback = useRef<() => void>();
// 等待所有任务执行完成的Promise
const awaitExeOver = () => {
return new Promise<void>((resolve, reject) => {
if (queue.current.length === 0 && executingNum.current === 0) {
resolve();
}
overCallback.current = () => {
resolve();
overCallback.current = undefined;
}
})
};
// 添加任务
const addTask = (task: QueueTask | QueueTask[]) => {
if (Array.isArray(task)) {
queue.current = queue.current.concat(task);
} else {
queue.current.push(task);
}
executeTask();
};
// 执行中的任务数量
const executingNum = useRef(0);
// 执行队列中的任务
const { run: executeTask } = useDebounceFn(() => {
// 凑齐同时执行的最大任务数量
while (executingNum.current < limit && queue.current.length > 0) {
const task = queue.current.shift(); // 获取队列中的第一个任务
if (task) {
executingNum.current += 1; // 更新执行中的任务数量
task.execute().then(res => {
executingNum.current -= 1; // 更新执行中的任务数量
console.log('执行任务', task.id, '执行结果', res, '当前执行中的任务数量', executingNum.current, '当前队列长度', queue.current.length);
if (queue.current.length === 0 && executingNum.current === 0) {
// 所有任务执行完成
overCallback.current?.();
} else {
// 继续执行队列中的任务
executeTask();
}
})
}
}
}, { wait: 300 });
return { addTask, awaitExeOver };
}
2. 使用方式:
useSyncQueue返回两个方法:
- addTask添加任务;
可单个添加,可数组添加;
任务对象QueueTask由唯一ID和获取异步Promise的execute方法组成;
添加任务后,会自动执行队列任务,直到队列为空 - awaitExeOver等待任务全部执行完;
要在添加过任务之后调用awaitExeOver方法;
执行awaitExeOver方法,才会创建回调方法overCallback;
队列为空时,执行overCallback,awaitExeOver方法等待结束;