设计思路
- 任务依赖管理:使用一个数据结构(如数组)来表示任务及其依赖关系。每个任务可以包含一个唯一标识、任务函数、依赖任务的标识列表。
- 异步迭代与执行:利用
for - await - of
循环结合异步迭代器来按顺序处理任务。确保在执行一个任务前,其所有依赖任务都已成功完成。
- 重试机制:为每个任务定义重试次数和重试间隔。当任务失败时,按照设定的重试次数和间隔进行重试。
- 性能优化:
- 避免过度等待:在等待依赖任务完成时,使用
Promise.race
来监控所有依赖任务的完成情况,而不是逐个等待。
- 有效管理重试:随着重试次数增加,适当增加重试间隔,避免短时间内大量重试请求对系统造成压力。
关键代码片段及解释
// 定义任务结构
const tasks = [
{ id: 'task1', fn: async () => { /* 任务逻辑 */ }, dependencies: [] },
{ id: 'task2', fn: async () => { /* 任务逻辑 */ }, dependencies: ['task1'] },
{ id: 'task3', fn: async () => { /* 任务逻辑 */ }, dependencies: ['task2'] }
];
// 异步迭代器生成函数
function* taskIterator(tasks) {
for (const task of tasks) {
yield task;
}
}
// 执行任务的主函数
async function executeTasks() {
const taskIter = taskIterator(tasks);
const completedTasks = new Map();
for await (const task of taskIter) {
const { id, fn, dependencies } = task;
// 等待所有依赖任务完成
const dependencyPromises = dependencies.map(depId => {
if (!completedTasks.has(depId)) {
throw new Error(`Dependency ${depId} not completed for task ${id}`);
}
return completedTasks.get(depId);
});
await Promise.race(dependencyPromises);
let retryCount = 3; // 重试次数
let retryInterval = 1000; // 初始重试间隔 1 秒
while (retryCount > 0) {
try {
const result = await fn();
completedTasks.set(id, Promise.resolve(result));
break;
} catch (error) {
retryCount--;
if (retryCount === 0) {
throw new Error(`Task ${id} failed after ${3 - retryCount} retries: ${error.message}`);
}
await new Promise(resolve => setTimeout(resolve, retryInterval));
retryInterval *= 2; // 每次重试间隔翻倍
}
}
}
}
executeTasks().catch(console.error);
- 任务结构定义:
tasks
数组定义了每个任务的唯一标识 id
、执行函数 fn
以及依赖任务的标识列表 dependencies
。
- 异步迭代器生成函数:
taskIterator
函数返回一个生成器,用于按顺序迭代任务。
- 执行任务主函数:
taskIter
是异步迭代器实例。completedTasks
用于记录已完成任务的结果。
- 在
for - await - of
循环中,针对每个任务,先通过 Promise.race
等待所有依赖任务完成。
- 任务执行失败时,按照设定的重试次数和逐渐翻倍的重试间隔进行重试。若最终仍失败,则抛出错误。