面试题答案
一键面试异步任务性能优化策略
- 任务并发控制
- 在 TypeScript 中,可以使用
Promise.all
来并发执行多个异步任务。但如果任务数量过多,可能会导致资源耗尽。例如,在进行大量网络请求时,过多的并发请求可能会使服务器压力过大,同时客户端网络带宽也可能被占满。 - 可以通过队列和计数器来实现并发控制。比如设置一个最大并发数
maxConcurrent
,当任务执行时计数器加一,任务完成时计数器减一,只有当计数器小于maxConcurrent
时,才从队列中取出新任务执行。
- 在 TypeScript 中,可以使用
- 资源复用
- 对于网络请求,可以复用网络连接池。在 Node.js 中,
http
模块的Agent
对象可以实现连接池功能。例如,在发起 HTTP 请求时,可以设置agent
选项来复用已有的连接。 - 文件读写方面,可以复用文件描述符。在 Node.js 中,通过
fs.open
打开文件获取文件描述符后,后续的读写操作都可以使用这个描述符,而不是每次读写都重新打开文件。
- 对于网络请求,可以复用网络连接池。在 Node.js 中,
异步任务管理模块设计思路
- 任务调度
- 采用队列的方式来管理任务。每个任务封装成一个函数,当任务加入队列时,按照一定规则(如先进先出)等待执行。
- 利用
async/await
来处理异步任务,使代码更简洁易读。
- 资源监控与回收
- 对于网络连接等资源,可以通过计数器记录资源的使用情况。当资源使用完毕(如网络请求完成),计数器减一,当计数器为 0 时,可以考虑回收资源(如关闭网络连接)。
- 对于文件描述符,在任务完成后,及时关闭文件描述符以释放资源。
关键代码示例
class TaskManager {
private taskQueue: (() => Promise<void>)[] = [];
private runningTasks: number = 0;
private maxConcurrent: number;
constructor(maxConcurrent: number) {
this.maxConcurrent = maxConcurrent;
}
addTask(task: () => Promise<void>) {
this.taskQueue.push(task);
this.executeNextTask();
}
private async executeNextTask() {
while (this.runningTasks < this.maxConcurrent && this.taskQueue.length > 0) {
const task = this.taskQueue.shift();
if (task) {
this.runningTasks++;
try {
await task();
} catch (error) {
console.error('Task execution error:', error);
} finally {
this.runningTasks--;
this.executeNextTask();
}
}
}
}
}
// 示例使用
const manager = new TaskManager(5);
// 模拟异步任务
const asyncTask1 = async () => {
// 模拟网络请求或文件读写等异步操作
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('Task 1 completed');
};
const asyncTask2 = async () => {
await new Promise(resolve => setTimeout(resolve, 1500));
console.log('Task 2 completed');
};
manager.addTask(asyncTask1);
manager.addTask(asyncTask2);
以上代码实现了一个简单的异步任务管理模块,通过设置最大并发数 maxConcurrent
来控制任务并发执行,利用队列来调度任务。同时,在任务执行完毕后,通过 finally
块来更新任务计数并继续执行下一个任务。