JavaScript 多任务异步执行详解¶
本文档详细介绍了如何使用 Web Worker 和 Promise 实现多任务的异步执行,以提高应用程序的性能和响应速度。
Web Worker 实现多任务异步执行¶
Web Worker 允许在后台线程中运行脚本,从而避免阻塞主线程,特别适合处理计算密集型任务。
概述¶
Web Worker 实现多任务异步执行,通过将任务分配给多个 Web Worker,可以有效地利用多核 CPU 提升任务处理效率,并保持主线程的响应性。
代码结构¶
worker.js:定义了每个 Web Worker 的逻辑,用于处理分配给它的子任务main.ts:主线程代码,负责创建和管理多个 Web Worker,并向它们发送任务数据
实现步骤¶
1. 创建 Web Worker¶
在 main.ts 中,首先定义一个 workers 数组来存储所有的 Web Worker 实例,并设置 workerCount 变量来跟踪剩余的 Worker 数量。
2. 初始化计时¶
记录开始时间,以便后续计算总耗时。
3. 创建并启动 Web Worker¶
使用 for 循环创建指定数量的 Web Worker,并为每个 Worker 设置消息接收和错误处理事件监听器。
for (let i = 0; i < workerCount; i++) {
const worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' });
workers.push(worker);
// 监听 Worker 发送的消息
worker.onmessage = function(event) {
console.log('从 Worker 收到的消息:', event.data);
workerCount--;
if (workerCount === 0) {
console.log('所有 Worker 已经完成任务。');
const endTime = Date.now();
console.log(`总耗时: ${endTime - startTime} 毫秒`);
workers.forEach(worker => worker.terminate());
}
};
// 监听 Worker 错误
worker.onerror = function(error) {
console.error('Worker 错误:', error);
workerCount--;
if (workerCount === 0) {
console.log('所有 Worker 已经完成任务。');
const endTime = Date.now();
console.log(`总耗时: ${endTime - startTime} 毫秒`);
workers.forEach(worker => worker.terminate());
}
};
// 发送数据给 Web Worker
worker.postMessage({
data: `Hello, Worker!`,
index: i,
});
}
4. Web Worker 处理逻辑¶
在 worker.js 中,每个 Web Worker 接收到主线程发送的数据后,会模拟一个耗时任务(使用 setTimeout),并在任务完成后向主线程发送消息。
self.onmessage = function(event) {
const { data, index } = event.data;
const start = Date.now();
console.log('接收到数据', data);
console.log('开始执行子任务', index);
setTimeout(() => {
console.log(`子任务${index}结束,耗时:`, Date.now() - start);
self.postMessage({ data });
}, index * 500);
};
运行结果¶
每个 Web Worker 在接收到任务后会立即开始执行,并在指定的时间间隔后完成任务。主线程会在所有 Web Worker 完成任务后输出总耗时,并终止所有 Web Worker。
注意事项¶
- 确保 worker.js 和 main.ts 文件路径正确
- Web Worker 的数量可以根据实际需求进行调整
- 在生产环境中,建议对 Web Worker 的通信和错误处理进行更详细的日志记录和异常处理
Promise 实现多任务异步执行¶
Promise 提供了一种更简洁的方式来处理异步操作,特别适合处理 I/O 操作等非计算密集型任务。
概述¶
使用 Promise 实现多任务异步执行,可以更方便地处理多个异步任务,并在所有任务完成后执行特定的操作。
实现步骤¶
1. 创建多个 Promise¶
在 main.ts 中,创建一个包含多个 Promise 的数组,每个 Promise 模拟一个耗时任务。
const tasks = [];
let taskCount = 10; // 任务的数量
const startTime = Date.now();
for (let i = 0; i < taskCount; i++) {
const task = new Promise((resolve, reject) => {
setTimeout(() => {
console.log(`任务${i}结束,耗时:`, Date.now() - startTime);
resolve(`任务${i}完成`);
}, i * 500);
});
tasks.push(task);
}
2. 使用 Promise.all 处理所有 Promise¶
使用 Promise.all 方法可以等待所有 Promise 完成,并在所有任务完成后执行特定的操作。
Promise.all(tasks)
.then(results => {
console.log('所有任务已经完成。');
console.log('任务结果:', results);
const endTime = Date.now();
console.log(`总耗时: ${endTime - startTime} 毫秒`);
})
.catch(error => {
console.error('任务错误:', error);
});
运行结果¶
每个 Promise 在接收到任务后会立即开始执行,并在指定的时间间隔后完成任务。主线程会在所有 Promise 完成任务后输出总耗时,并显示所有任务的结果。
注意事项¶
- 确保每个 Promise 的逻辑正确,并且能够正确地 resolve 或 reject
- 在生产环境中,建议对 Promise 的错误处理进行更详细的日志记录和异常处理
对比与选择¶
Web Worker 的优势¶
- 多线程处理:Web Worker 可以在独立的线程中执行任务,不会阻塞主线程,适合处理耗时的计算密集型任务
- 资源隔离:每个 Web Worker 都有自己的全局作用域,避免了主线程和 Worker 之间的变量冲突
- 更好的性能:通过利用多核 CPU,可以显著提高任务处理效率
Promise 的优势¶
- 简洁的语法:使用 Promise 可以更简洁地处理多个异步任务,避免了回调地狱
- 更好的可读性:Promise 的链式调用使得代码更易读和维护
- 错误处理:Promise 提供了更方便的错误处理机制,可以通过
.catch方法统一处理错误
选择合适的方案¶
- Web Worker:适用于需要在独立线程中执行的耗时任务,特别是计算密集型任务
- Promise:适用于需要在主线程中处理的异步任务,特别是 I/O 操作或其他非阻塞任务
通过合理选择和结合使用 Web Worker 和 Promise,可以更好地利用 JavaScript 的异步特性,提高应用程序的性能和响应速度。