webWorker基本用法

我们都知道js是一个单线程的语言,当线程堵塞时,可能会导致页面无法正常交互,如一些复杂的可视化处理。即使是异步处理,也只是将其暂存到任务队列中去,等主线程执行完后依然会从任务队列中取过去。

为此,js提供了一种多线程效果的处理方式--webWorker,下面来用一段实力来展示:

基本示例(这里在一个vue项目中展示)

1.先创建一个webWorker对应的js文件

注:由于webworker构造函数接收的路径需要是线上的地址,因此在开发过程中可以放到public文件夹中(如example.js)这样,通过 项目启动地址+文件名即可访问该文件。

这样通过http://127.0.0.1:5173/example.js 即可访问该文件,并看到该文件内容:

2.在想要使用webWorker的方法中,创建一个webWorker对象(参数为上面的地址,本示例中的http://127.0.0.1:5173/example.js);不用本地地址的原因后续会说。

html 复制代码
<button @click="startWebWorker">点我触发webWorker</button>
javascript 复制代码
startWebWorker() {
  // 创建一个webWorker对象
  let myWorker = new Worker("http://127.0.0.1:5173/example.js")
},

这样,当点击此按钮时,会调用example.js中的脚本内容输出"hello world"。

3.postMessage方法:

通过postMessage可以向webWorker中传递参数(不可为函数):

javascript 复制代码
startWebWorker() {
  // 创建一个webWorker对象
  let myWorker = new Worker("http://127.0.0.1:5173/example.js")
  myWorker.postMessage("hello webWorker");
},

4.接收传过来的数据:

这里可以通过监听message事件来获取到数据。(webWorker对应文件中使用self进行postMessage等相关操作)

example.js中:

javascript 复制代码
// console.log("hello world")
self.addEventListener("message", (res) => {
    console.log(res.data); // 输出 hello webWorker
})

(ps,也可以使用self.onmessage来获取)

5.反向传递信息

其原理与上面的类似,同样使用postMessage,与监听message来实现:

示例vue文件中的方法:

javascript 复制代码
startWebWorker() {
  // 创建一个webWorker对象
  let myWorker = new Worker("http://127.0.0.1:5173/example.js")
  myWorker.postMessage("发送的信息:hello webWorker");
  myWorker.addEventListener("message", (res) => {
    console.log("返回的信息:" + res.data)
  })
},

example.js中:

javascript 复制代码
// console.log("hello world")
self.addEventListener("message", (res) => {
    console.log(res.data); // 输出 hello webWorker
    self.postMessage("nice to meet you too!");
})

结果:

6.补充:

比如说 public/example.js 中想要使用 public/test.js 中的方法:

public/test.js:

javascript 复制代码
function testFun() {
    console.log('我是testFun')
}

public/example.js:(这里直接这样引用会报错)

javascript 复制代码
import "./test.js"
testFun();

需改为以下引发:

javascript 复制代码
// import "./test.js"
importScripts("http://127.0.0.1:5173/test.js")
testFun()

当然有一种例外,就是test.js中使用的es6的module:

public/test.js:

javascript 复制代码
export function testFun() {
    console.log('我是testFun')
}

报错:Uncaught SyntaxError: Cannot use import statement outside a module

此时就不能用importScripts了,需要在创建webWorker对象时声明type为module

示例vue文件中的 创建一个webWorker对象 部分:

javascript 复制代码
// 创建一个webWorker对象
let myWorker = new Worker("http://127.0.0.1:5173/example.js", {
    type: "module"
})

public/example.js:

javascript 复制代码
import { testFun } from "./test.js"
// importScripts("http://127.0.0.1:5173/test.js")
testFun()

这样就生效了。

webWorker注意事项

1.webWorker文件中的方法不可操作节点。

2.postMessage方法不可传递function方法。

3.new Worker参数不可为本地文件,可使用线上地址(如发布出去)。

4.在webWorker文件中若想使用第三方库的方法(如导出excel),可以通过cdn引入,或者将node_modules关键文件以同样方式(放入public或发布)引入。

单线程堵塞处理实例

1.堵塞简单示例,最简单的,遍历百亿次(电脑好可以更多,根据务必电脑情况斟酌):

html 复制代码
<button @click="startWebWorker">遍历一亿次</button>
信息:<input />
javascript 复制代码
startWebWorker() {
  let total = 0
  for(let i = 0; i< 10000000000; i++) {
    total++;
  }
  console.log("结果是:" + total);
},

在结果输出前,你会发现输入框处于无法交互状态,整个页面都被堵塞所影响了,这个是异步也很难解决的问题。

因此,这里可以借助webWorker来实现:

javascript 复制代码
startWebWorker() {
  // 创建一个webWorker对象
  let myWorker = new Worker("http://127.0.0.1:5173/example.js");
  myWorker.postMessage("开始遍历");
  myWorker.onmessage = (res) => {
    console.log("结果是:" + res.data);
  }
},

public/example.js:

javascript 复制代码
self.addEventListener("message", (res) => {
    if(res.data == "开始遍历") {
        let total = 0
        for(let i = 0; i< 10000000000; i++) {
          total++;
        }
        self.postMessage(total)
    }
})

这样,堵塞就因 webWorker多线程 的缘故而不会影响页面(如:输入框)的正常交互了。

希望本文会对您有所帮助 ^_^ ~

相关推荐
跨境数据猎手5 分钟前
跨境电商系统三大 Web 漏洞的防护:SQL 注入、XSS、CSRF
前端·sql·xss
冒险的豆子40 分钟前
Proxy & Vue 响应式(合并精简版,适合面试)
前端·javascript·vue.js
Java后端的Ai之路1 小时前
前端技术Vue-18-视图中的渲染
前端·javascript·vue.js
程序员海军7 小时前
用了两年多 GPT,我最近开始换模型了,还折腾了个求职避坑 Agent
前端·人工智能·后端
zttbee8 小时前
echarts图表tooltip色块失效
前端·javascript·echarts
excel9 小时前
IndexNow:让搜索引擎更快发现网站更新的主动通知协议
前端·后端·架构
子兮曰10 小时前
CSS 复现 23 种设计风格:从拟物到液态玻璃的成本阶梯与兜底写法【实战】
前端·css·视觉设计
虚无境10 小时前
如何用AI帮我写出实用的插件
前端·javascript·ai编程
柳杉11 小时前
从数字化到数智化:3D 可视化大屏的下一个五年
前端·ai编程·数据可视化
濮水大叔11 小时前
函数式与对象式:前端架构的两种成本曲线
vue.js·react.js·函数式编程