页面进行大量数据计算时,操作页面没反应怎么办?webWorker来解决

86 阅读3分钟

用于优化js的耗时运算,因为js 是单线程的,有些数据量大或很麻烦的数据运算的时候可能会阻塞主线程,导致页面卡顿,因此 webWorker的诞生就是为了解决这个问题,它可以将耗时的数据运算放到后台运行,和主线程进行通信,不占用主线程,从而解决了阻塞。

优势总结:

  1. 解放主线程:可以将webscoket连接这种持久连接通信放在 webworker中处理,避免阻塞主线程。这样耗时运算在后台运行了,页面不会被阻塞导致卡死,其他地方点了没反应啥的,但是并没有将运算时间缩短。
  2. 独立在后台运行不受主线程影响,比如即使用户关闭了网页,仍然可以保持 webscoket 连接实现离线消息推送等功能。
  3. 分布式计算:通过将耗时运算或者持久连接ws放在 web Worker 或者 service Worker 中 可以实现分布式计算,将计算任务分散到多个浏览器实例中进行处理,提高计算效率。

tip:如果页面卡顿不知道什么问题,可以用最小单元测试的方法来排除:

比如怀疑很耗时的数据运算方法导致的,可以将他们先替换成计算好的数据直接返回,看看是否还有卡顿现象,如果不卡了,说明就是运算导致可以将运算提出来放到 webWorker 中处理。

使用 webWorker 注意事项:

  1. webWorker中没有 DOM(document等),BOM(window等),纯JS语法都是可以用的,所有有关涉及到Dom操作的内容不能放在worker中,可以把处理好的数据传给主线程中处理。
  2. webWorker 不能用本地文件,只能用网络上的同源文件,因此可以放到静态资源下,或者部署到服务器的指定的静态资源里
  3. 不是所有东西都可以从主进程传递过去的,只能传递数据,不能传递函数,DOM节点,还有一些对象里的特殊设置(freeze,getter,setter 等) ,所以Vue的响应式对象是不能传递的
  4. 使用完成后没必要用了的话需要关闭他,为了节省系统资源 ,必须关闭他。
  5. 模块的引入问题:

直接 new Worker("http://www.xxx.com/A.js") 创建的worker文件是不直接支持 ES Module模块化的,或者需要支持 80 之前版本的 Chrome的话(因为从 Chrome 80+ 才开始支持 ES Module 模块化),想要在 A.js 中引入第三方文件需要用 :

importScripts('http://www.xxx.com/XXX.js')//不限制必须同源,都可以引入

const a = 1+1;
self.postMessage(a)

这种引入方式用于:不支持模块化的运行环境、引入非模块化的包(纯js包,iife 那种)。

但是这种引入方式有缺点:引入的代码会全部执行,无法按需引入。

在支持ES Module的浏览器这样写:这样就能使用import 、export了。用于引入esm的包。

 const worker1 = new Worker("http://www.xxx.com/A.js",{
   type:module
 })

要是引入node_modules 中的库的话,可以从node_modules中找到该库的js包 复制到public下去引入。

基本使用方法:

  const tableDataWorker = new Worker("/tableDataWorker.js", {
    type: "module",
  });
  tableDataWorker.postMessage("nihao");
  tableDataWorker.addEventListener("message", (e) => {
    console.log(e, "hookeeeeeeeeeeeee");
  });
const a = 12343423;
self.postMessage(a);
self.addEventListener("message", (e) => {
  console.log(e, "workereeeeee");
});

相关参考:

www.ruanyifeng.com/blog/2018/0…