关于web woker那些事儿

一、简介
1、作用

js为单线程,但web workers可以使得一些涉及复杂计算的逻辑在独立的线程运行,从而不会影响页面的性能,例如渲染、交互响应等(本质为主线程专注ui渲染)

2、局限性

不能操作DOM、作用域独立等

3、分类

DediactedWorker: 线程只能与一个页面渲染进程进行绑定和通信,不能多 Tab 共享
SharedWorker: 可以多个浏览器 Tab 中访问到同一个 Worker 实例,实现多 Tab 共享数据,共享 websocket 等(safari 放弃了 SharedWorker 支持)

4、浏览器扩展

主线程: 管理内容渲染和用户交互,包含步骤:JavaScript -> Style -> Layout -> Paint -> Composit

5、兼容性

关于web woker那些事儿_第1张图片

二、基本使用

主线程和worker通过postMessageonmessage来通信。

// index.html
const worker = new Worker('./worker.js');
// 向worker发送消息。
worker.postMessage('start');
// 接受worker发送的消息
worker.onmessage = function onmessage(ev) {
  document.getElementById('result').innerHTML = ev.data;
  if (ev.data === 10) worker.terminate();
};
// worker.js
onmessage = function (ev) {
  if (ev.data === 'start') {
    timedCount();
  }
};
const timedCount = function timedCount() {
  i += 1;
  // 向主线程发送消息
  postMessage(i);
  setTimeout(timedCount, 500);
};
三、在vue中使用web worker

在vue3中的使用

1、安装
yarn add worker-loader
2、配置webpack

在vue.config.js文件的defineConfig里加上配置参数

  chainWebpack: config => {
    config.module
      .rule('worker-loader')
      .test(/\.worker\.js$/)
      .use({
        loader: 'worker-loader',
        options: {
          inline: true
        }
      })
      .loader('worker-loader')
      .end()
  }

3、使用
// vue页面
import Worker from 'worker-loader!./js/worker'; // 注意后面为文件路径

const makeWorker = () => {
  // 获取计算开始的时间
  const start = performance.now();
  // // 新建一个线程
  const worker = new Worker();
  // 线程之间通过postMessage进行通信
  worker.postMessage(0);
  // 监听message事件
  worker.addEventListener('message', (e: any) => {
  	// 关闭线程
  	worker.terminate();
  	// 获取计算结束的时间
  	const end = performance.now();
  	// 得到总的计算时间
  	const durationTime = end - start;
  	console.log('分线程计算结果:', e.data);
  	console.log(`分线程代码执行了 ${durationTime} 毫秒`);
  });
};
// worker.js
onmessage = function (e) {
  // onmessage获取传入的初始值
  let sum = e.data;
  for (let i = 0; i < 200000; i++) {
    for (let i = 0; i < 10000; i++) {
      sum += Math.random();
    }
  }
  // 将计算的结果传递出去
  postMessage(sum);
};

在vue2中的使用
安装

yarn add vue-worker

引入

import VueWorker from 'vue-worker'
Vue.use(VueWorker)

主页面

import worker from "./transformDataToTree";

this.$worker.run(worker, [参数],then(res1, res2)=>{
	// 一些逻辑执行之后的回调操作
})

worker.js

export default (接收到的参数) => {
	// 一些执行逻辑
	const treeData1 = []
	const treeData2 = []
	return {
		res1: treeData1, // 返回的数值可以在主页面回调中接收
		res2: treeData2
	}
}

备注:
1、vue项目中,若直接使用Web Worker,会遇到worker文件路径与打包解析的问题
2、vue2中适合使用vue-worker, 若在vue3中使用的话,web-worker库会报Object.defineProperty called on non-object的错误

三、Shared worker

Shared worket提供了一种跨窗口/iframe等通信的途径(同源通信)
注: chrome浏览器通过chrome://inspect/#workers进入可查看线程

1、SharedWorker 标识

线程标识源自解析后的脚本 URL、工作者线程名称和文档源(第二个参数为SharedWorke名称),任何一个不同都会创建新的进程
以命名为例

const worker = new SharedWorker("./js/shareWorker.js", 'page1');
const worker = new SharedWorker("./js/shareWorker.js", 'page2');

命名不同会导致产生两个线程
关于web woker那些事儿_第2张图片

2、使用

shareWorker.js

// 记个数
let count = 0;
// 把每个连接的端口存下来
const ports = [];

// 连接函数 每次创建都会调用这个函数
onconnect = (e) => {
  console.log("这里是共享线程展示位置");
  // 获取端口
  const port = e.ports[0];
  // 把丫存起来
  ports.push(port);
  // 监听方法
  port.onmessage = (msg) => {
    // 这边的console.log是看不到的 debugger也是看不到的 需要在线程里面看
    console.log("共享线程接收到信息:", msg.data, count);
    if (msg.data === "+") {
      count++;
    }
    // 循环向所有端口广播
    ports.forEach((p) => {
      p.postMessage(count);
    });
  };
};

page1.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>SharedWorker-page1</title>
  </head>
  <body>
    <h1>SharedWorker-page1</h1>
    <button onclick="workerClick()">count++</button>
    <script>
      // 兼容性判断
      if (!SharedWorker) {
        throw new Error("当前浏览器不支持SharedWorker");
      }
      // 创建
      const worker = new SharedWorker("./js/shareWorker.js", 'page1');
      // 启动
      worker.port.start();
      // 线程监听消息
      worker.port.onmessage = (e) => {
        console.log("page1共享线程计数值:", e.data);
      };
      const workerClick = () => {
        worker.port.postMessage('+');
      };
    </script>
  </body>
</html>

page2.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>SharedWorker-page2</title>
  </head>
  <body>
    <h1>SharedWorker-page2</h1>
    <button onclick="workerClick()">count++</button>
    <script>
      const btn = document.querySelector('#btn');
      // 兼容性判断
      if (!SharedWorker) {
        throw new Error('当前浏览器不支持SharedWorker');
      }
      // 创建
      const worker = new SharedWorker('./js/shareWorker.js', 'page2');
      // 启动
      worker.port.start();
      // 线程监听消息
      worker.port.onmessage = (e) => {
        console.log('page2共享线程计数值:', e.data);
      };
      const workerClick = () => {
        worker.port.postMessage('+');
      };
    </script>
  </body>
</html>

三、使用场景
1、大数据卡顿

数据处理逻辑放入worker中处理即可

2、离屏Canvas ,使用Web Worker提高你Canvas运行速度

Canvas计算和渲染和用户操作响应都发生在同一个线程,会耗时产生页面卡顿问题.
OffscreenCanvas 离屏Canvas将渲染与DOM完全分离,正因为不依赖dom,所以可以在计算过程可以在worker中进行,避免阻塞住进程.

2、跨窗口/iframe通信(Shared worker)

你可能感兴趣的:(前端,javascript,web,worker)