Web Workeropen in new window 可以实现将复杂、耗时的计算从 JavaScript 的主执行进程中抽离出来,以后台任务的形式运行,避免影响主执行进程。Web Worker 无法操作 DOM 元素。

在前面设置构建输出目标一章中我们介绍过构建 Web Worker 的配置,这里我们介绍一下具体的使用方法。

添加一个 worker

一个 Worker 需要关注两件事情,一个是接收消息,一个是响应消息。在这之前,Worker 进行计算处理。

src/worker.js

self.onmessage = ({ data: { text } }) => {
  self.postMessage({ text: text + text });
};
1
2
3

添加一个宿主

宿主需要初始化 Worker 并与 Worker 进行通信。

src/component.js

export default (text = HELLO) => {
  const element = document.createElement('h1');
  const worker = new Worker(new URL('./worker.js', import.meta.url));
  const state = { text };

  worker.addEventListener('message', ({ data: { text } }) => {
    state.text = text;
    element.innerHTML = text;
  });
  element.innerHTML = state.text;
  element.onclick = () => worker.postMessage({ text: state.text });

  return element;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14

完成这两步以后,我们就可以实现按钮的文案来自于 worker 计算的结果了。我们还可以将 worker 的响应改成异步的形式,加一些延时,看看按钮的变化。

数据共享

考虑到 Worker 与宿主间通信过程中数据序列化的开销,我们可以通过 Transferable objectsopen in new window 来降低序列化的开销,同时还可以考虑使用 SharedArrayBufferopen in new window 来共享数据。

其他选择

在 Webpack 5 之前,我们可以使用 worker-loaderopen in new window 来构建 Worker,现在依然可以使用,worker-loader 提供了更加细粒度的配置。

借助于 workerize-loaderopen in new windowworker-pluginopen in new window 我们可以想普通 JavaScript 模块一样定义 Worker,同时还可以避免使用上面样例中 self

threads.jsopen in new window 提供了功能更加丰富,也更加复杂的解决方案。Thread.js 提供了可观察对象、线程池等特性。我们可以通过 threads-pluginopen in new window 将其与 Webpack 结合起来。

总结

Web Worker 可以将复杂的计算等任务从 JavaScript 主执行进程中剥离出来,作为后台任务运行。Worker 无法直接操作用户 UI。

Web Worker 的通信开销比较大,不过随着上面介绍的一些技术的发展,这个问题将会得到改善。

关注微信公众号,获取最新推送~