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多线程 的缘故而不会影响页面(如:输入框)的正常交互了。

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

相关推荐
林太白1 分钟前
Nuxt3 功能篇
前端·javascript·后端
YuJie2 分钟前
webSocket Manager
前端·javascript
Mapmost17 分钟前
Mapmost SDK for UE5 内核升级,三维场景渲染效果飙升!
前端
Mapmost20 分钟前
重磅升级丨Mapmost全面兼容3DTiles 1.1,3DGS量测精度跃升至亚米级!
前端·vue.js·three.js
wycode26 分钟前
Promise(一)极简版demo
前端·javascript
浮幻云月27 分钟前
一个自开自用的Ai提效VsCode插件
前端·javascript
DevSecOps选型指南29 分钟前
SBOM风险预警 | NPM前端框架 javaxscript 遭受投毒窃取浏览器cookie
前端·人工智能·前端框架·npm·软件供应链安全厂商·软件供应链安全工具
__lll_37 分钟前
Docker 从入门到实战:容器、镜像与 Compose 全攻略
前端·docker
木春1 小时前
react组件化思维:高复用性 UI 设计之道
前端·react.js