Web Worker

一、前言

借用 MDN 的描述,Web Worker 是在后台线程中执行脚本的简单方法,可以在不阻塞用户界面的情况下执行任务。

在 worker 中执行的代码不用担心阻塞用户界面,可以放心的执行一些计算密集型的任务。但是也不能过度使用,并且应该在任务结束后及时关闭 worker,减少系统资源消耗。

由于 worker 运行在与主线程不同的上下文中,所以在编写 worker 中执行的代码时有一些要注意的差异:

没有 window 对象,worker 中的全局对象 是 self self 中没有 document 对象,也没有 alert() confirm() 等方法,但 navigator location XMLHttpRequest 等对象以及 setTimeout() setInterval() 等方法是可以正常使用的。
无法与主线程直接通信 只能通过 postMessage 和 onmessage 这两个方法发送/接收消息,允许传递对象,但是以深拷贝的形式传递。
共享 worker 的使用上与专用 worker 有所差异,主要区别是共享 worker 通信时需指定端口号,并且允许被多个 窗口/iframe/worker 访问。具体可查看 MDN 介绍,我只使用了专用 worker 。
此外,也许基于安全等考量,web worker 的使用还有另外的一些限制:

同源限制 worker 中执行的代码必须放到脚本文件中,且该脚本文件的拉取必须遵守同源策略。
DOM 限制 worker 中不能读取和操作 DOM 对象。

二、使用

2.1 示例

// 主线程
const worker = new Worker('test.worker.js');
worker.postMessage('start', {data: {});
worker.onmessage = function(event) {
  const {type, data} = event;
  if (type === 'end') {
  	worker.postMessage({type: 'end', data: ''})
  }
}

// public/test.woker.js
console.log('start worker selg:', self);
self.onmessage = function(event) {
  const {type, data} = event.data;
  if (type === 'start') {
    ....
    self.postMessage({type: 'finish', data: ''});
    self.close(); // 关闭 worker
  }
}

主线程和 worker 双方的收发消息方式都是完全一样的。通过 event.data 可以拿到对方传递的消息,具体的消息结构由我们自己定义。

2.2 终止 worker

// 可以直接调用 terminate 方法强制结束 worker 线程
worker.terminate(); // 强行终止 worker

// 可以通过消息来告知 worker 主动退出
// 主线程
worker.postMessage('stop');

// public/test.worker.js
self.onmessage = function(event) {
  const {type} = event.data;
  if (type === 'stop') {
    ...
    self.close(); // 关闭 worker
  }
}

2.3 异常处理

// public/test.worker.js
self.onerror = function (event) {
  thisWorker.postMessage({ type: 'error', event })
}

// 主线程
const worker = new Worker('test.worker.js');
worker.onmessage = function(event) {
  if (event.data.type === 'error') {
    ...
  }
}
或
worker.onerror= function(event) {
  if (event.data.type === 'error') {
    ...
  }
}

2.4 加载脚本

importScripts(); /* 什么都不引入 */
importScripts("test.js"); /* 只引入 "test.js" */
importScripts("//example.com/hello.js"); /* 其他来源导入脚本 */

// importScripts 是同步的,所有脚本拉取完毕后才会返回

三、worker-loader
importScripts 只能加载网络文件,无法拉取源代码。woker.js 文件必须放到 /public 文件夹下(或其他可通过同源策略加载的网络地址中)。这意味着没办法复用源码中的一些公共逻辑。
webpack4,要解决这个问题,在 worker 中方便的复用公共逻辑,需要使用 worker-loader 插件。
webpack5 已经原生支持引用源码,不再需要 worker-loader。

new Worker(new URL('./worker.js', import.meta.url));

3.1 安装

yarn add -D worker-loader 

3.2 配置vue.config.js

// vue.config.js

module.exports = {
     // other config

    chainWebpack: (config) => {
        // other config

        /** web worker 支持 */
        config.module
          .rule('worker')
          .test(/\.worker\.js$/)
          .use('worker-loader')
          .loader('worker-loader')
          .end()
    }
}

3.3 使用

// test.vue

<script>
import testWorker from '@/common/test.worker.js'

export default {
	...
  methods: {
    startWorker() {
      const worker = new testWorker () 
      worker.postMessage('start', {data: {});
      worker.onmessage = function(event) {
        ...
      }
    }
  }
}
</script>

// src/common/test.worker.js
import logic from './logic '

if (self) {
  self.onerror = function (event) {
    self.postMessage({ type: 'error', event })
    self.close()
  }
  self.onmessage = function (event) {
    const { type } = event.data
    if (type === 'start') {
      const res = logic (event.data)
      self.postMessage({ type: 'finish', data: res })
      self.close()
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值