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>();// 等待所有任务执行完成的Promiseconst 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方法等待结束;