在 React 中使用 Web Workers

3,882 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

什么是 web worker?

JavaScript 是一种单线程的语言,Web worker 的作用就是为 JavaScript 创造多线程环境。允许主线程创建 Workder 线程,将一些任务分配给后者运行,主线程运行的同时,worker 线程也在运行,相互不干扰,等 worker 线程运行完后,把结果返回给主线程。

使用

主线程发送和接受数据

// 主线程 index.js 
// 创建一个 worker 
const worker = new Worker('./worker.js'); 
// 发送消息 
worker.postMessage('Hello World'); 
// 接受数据 
worker.onmessage = function(e) { 
    console.log(e.data); // 这里可以对接受到的数据进行一些处理 
    console.log('Message received from worker'); 
} 
// 终止 
worker worker.terminate(); 
// 错误处理 
worker.onerror = function(e) => { }

worker 线程对数据进行二次加工,一般处理一些比较耗时的任务(比如代码高亮)

// worker 线程 worker.js
onmessage = function (e) {
	// 一些复杂的计算或者耗时的事情
	const msg = `post-msg-${e.data}`;
	postMessage(msg);

	// 在 worker 线程内部可以是 close() 来关闭
}

ps:

  • 在主线程中,使用 onmessage 和 posMessage() 必须挂在 worker 对象上。
  • 而在 worker 线程中不需要这么做,因为在 worker 线程内部,worker 是有效的全局作用域

数据传递

主线程与 worker 线程的数据传递是值拷贝的关系,即是传值而不是地址。意味着在 worker 中修改通信的数据,主线程中的内容不会被修改。

局限性

一个 worker 运行一个 JavaScript 文件,这个文件即在 worker 线程上运行的代码。

worker 运行在一个不同于 window 的全局上下文中,因此在 worker 内通过 window 获取全局作用于将会返回错误。

  • 不能直接操作 DOM 节点
  • 不能使用 window 对象的默认方式和属性,不过可以使用 WebSockets、IndexedDB 等数据存储机制,具体可以查看 developer.mozilla.org/en-US/docs/…

在 React 中使用 Web Workers

web worker 需要指定一个脚本的 URI,而在 React 的实际项目中,我们一般都会和打包工具一起使用(比如:webpack),这时如果直接引用文件,就会发生错误

// index.tsx
const worker = new Worker('./worker.ts')

解决方式

如果使用 webpack ,可以通过 worker-loader 来解决,配置如下:

{
  module: {
    rules: [
      {
           test: /\.worker\.ts$/,
           use: [
                {
                    loader: 'worker-loader',
                    options: {
                        inline: 'fallback',
                    },
                },
                {
                    loader: 'ts-loader',
                },
           ],
      }
    ]
  }
}

worker-loader 会把文件加载为 web worker,我们只需要把文件名命名为 /\.worker\.ts$/ 格式,比如 msg.worker.ts

可能会遇到问题

  1. 在使用了web worker 的页面,多次操作后,页面出现卡顿或者直接卡死

可能原因:

检查多次操作后,页面是否存在多个 web worker。修改创建 web worker 的逻辑,使页面不要同时出现 n 个 web worker

引用