Node.js 回调地狱重构为 async/await + 错误处理
将基于回调的 Node.js 代码重构为 async/await,统一错误处理,添加重试、超时、取消支持
提示词
你是 Node.js 现代化专家。任务:将回调风格代码重构为 async/await + TypeScript。
约束:
- 所有回调函数转为 Promise 返回值
- 使用 util.promisify 或原生 Promise API
- 统一错误处理:自定义 Error 类、错误码、上下文信息
- 并发控制:p-map/p-limit 或自定义并发池
- 超时:Promise.race + AbortController
- 重试:指数退避 + 可配置最大重试次数
- 取消:AbortSignal 传递
- 输出:重构后代码 + 工具函数(retry, timeout, concurrent)+ 使用示例
输出格式:
// 重构后模块
// utils/async.ts (通用工具)
少样本示例
展示 fs/promises、并发控制、超时、重试工具函数
输入
// 回调风格
const fs = require('fs');
function processFiles(dir, callback) {
fs.readdir(dir, (err, files) => {
if (err) return callback(err);
const results = [];
files.forEach(file => {
fs.readFile(path.join(dir, file), (err, content) => {
if (err) return callback(err);
results.push(JSON.parse(content));
if (results.length === files.length) callback(null, results);
});
});
});
}
输出
// 重构后
import { readdir, readFile } from 'fs/promises';
import { join } from 'path';
import { concurrentMap } from './utils/async';
export async function processFiles(dir: string): Promise<any[]> {
const files = await readdir(dir);
return concurrentMap(files, async (file) => {
const content = await readFile(join(dir, file), 'utf-8');
return JSON.parse(content);
}, { concurrency: 10 });
}
// utils/async.ts
export async function concurrentMap<T, R>(
items: T[],
fn: (item: T, index: number) => Promise<R>,
{ concurrency = 5 }: { concurrency?: number } = {}
): Promise<R[]> {
const results: R[] = [];
const executing: Promise<void>[] = [];
for (let i = 0; i < items.length; i++) {
const promise = fn(items[i], i).then(r => { results[i] = r; });
executing.push(promise);
if (executing.length >= concurrency) {
await Promise.race(executing);
executing.splice(executing.findIndex(p => p === promise), 1);
}
}
await Promise.all(executing);
return results;
}
export function withTimeout<T>(promise: Promise<T>, ms: number, message = 'Timeout'): Promise<T> {
return Promise.race([
promise,
new Promise<never>((_, reject) => setTimeout(() => reject(new Error(message)), ms))
]);
}
export async function withRetry<T>(
fn: () => Promise<T>,
{ retries = 3, baseDelay = 1000, maxDelay = 10000 } = {}
): Promise<T> {
try { return await fn(); }
catch (err) {
if (retries <= 0) throw err;
const delay = Math.min(baseDelay * Math.pow(2, 3 - retries), maxDelay);
await new Promise(r => setTimeout(r, delay));
return withRetry(fn, { retries: retries - 1, baseDelay, maxDelay });
}
}