Skip to content

HTML Web Workers

Web Workers 允许你在一个后台线程中运行 JavaScript 代码,从而防止复杂的或长时间运行的脚本冻结主浏览器界面。

通常情况下,JavaScript 代码在浏览器的一个单独线程(主线程)中运行。如果一个脚本执行时间过长(例如,复杂的计算、处理大量数据),它会阻塞主线程。这会使网页无响应——点击无效、动画卡顿,用户体验大受影响。

Web Worker 在一个单独的后台线程中运行脚本。这使得主线程可以保持响应,处理用户交互和 UI 更新,而 Worker 在后台执行其任务。

可以将其想象成将一项耗时的任务委托给助手,这样你就可以在不中断的情况下继续进行主要工作。

用例包括:图像处理、数据分析、后台数据抓取/同步、复杂计算。

Web Workers 已被所有现代网络浏览器广泛支持(Chrome、Firefox、Safari、Edge)。

使用 Web Workers 涉及三个主要步骤:

创建一个单独的 JavaScript 文件(例如,my_worker.js),其中包含你希望在后台运行的代码。

Worker 使用 postMessage() 方法将数据发回,并使用 onmessage 事件处理程序接收数据,与主线程通信。

// 在 my_worker.js 文件内
console.log('Worker started');
// 监听来自主线程的消息
self.onmessage = function(event) {
console.log('Worker received:', event.data);
const number = event.data;
const result = number * 2; // 执行一些任务
// 将结果发送回主线程
self.postMessage(result);
};
// 你也可以在不等待消息的情况下发送消息
// self.postMessage('Worker is ready!');

注意:self 指的是 Worker 的全局作用域。

在你主 HTML 页面的脚本中,首先检查浏览器是否支持 Workers。然后,创建一个新的 Worker 对象,传入你的 Worker 脚本文件的路径。

// 在主脚本内(例如,在 <script> 标签或 main.js 文件中)
let myWorker;
if (window.Worker) { // 检查浏览器支持
console.log('Worker support detected.');
myWorker = new Worker('my_worker.js');
// 添加事件监听器以接收来自 Worker 的消息
myWorker.onmessage = function(event) {
console.log('Main thread received:', event.data);
// 更新 UI 或使用结果
document.getElementById('result').textContent = `Result from worker: ${event.data}`;
};
// 可选:处理来自 Worker 的错误
myWorker.onerror = function(error) {
console.error('Worker error:', error.message, error);
};
} else {
console.log('Web Workers not supported in this browser.');
document.getElementById('result').textContent = 'Web Workers not supported.';
}

在主脚本中使用 worker.postMessage(data) 将数据发送到 Worker。

在主脚本中使用 worker.onmessage 事件处理程序接收来自 Worker 的数据。

// 示例:在 Worker 创建后发送数据
if (myWorker) {
const valueToSend = 10;
console.log('Main thread sending:', valueToSend);
myWorker.postMessage(valueToSend);
}
// HTML 中的结果元素:
// <p>Result: <output id="result">Waiting...</output></p>

Web Workers 消耗系统资源。在不再需要时终止它们以释放资源是很重要的。

在主脚本中,使用 Worker 对象的 terminate() 方法:

if (myWorker) {
myWorker.terminate();
myWorker = undefined; // 清理变量
console.log('Worker terminated.');
}

Worker 也可以从 Worker 脚本内部使用 self.close() 关闭自身。

由于它们在单独的线程中运行,Web Workers 存在一些限制:

  • 无法直接访问 DOM: Worker 无法直接访问或操作 HTML DOM(例如,document 对象)。它们必须通过 postMessage() 与主线程通信来请求 UI 更新。
  • 对 window 对象的访问受限: 它们无法访问 window 对象的许多属性(例如 window.alert)。它们可以访问一些 Web API,如 fetch()、WebSocket、IndexedDB 和 setTimeout/setInterval。
  • 无法访问父页面变量: 它们在自己的作用域中运行,无法直接访问创建它们的脚本中的变量或函数。
  • Shared Workers(共享工作线程): 可以被多个脚本(来自同一来源),可能在不同窗口或 iframe 中运行的脚本访问。
  • Service Workers(服务工作线程): 充当浏览器和网络之间的代理服务器。它们支持离线缓存、推送通知和后台同步等功能,即使页面未打开时也如此。它们与标准 Web Worker 有不同的生命周期和用途。

更多详细信息,请查看 MDN guide on Web Workers。