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

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

相关推荐
敲敲了个代码3 小时前
从硬编码到 Schema 推断:前端表单开发的工程化转型
前端·javascript·vue.js·学习·面试·职场和发展·前端框架
张雨zy4 小时前
Pinia 与 TypeScript 完美搭配:Vue 应用状态管理新选择
vue.js·ubuntu·typescript
dly_blog4 小时前
Vue 响应式陷阱与解决方案(第19节)
前端·javascript·vue.js
消失的旧时光-19434 小时前
401 自动刷新 Token 的完整架构设计(Dio 实战版)
开发语言·前端·javascript
console.log('npc')5 小时前
Table,vue3在父组件调用子组件columns列的方法展示弹窗文件预览效果
前端·javascript·vue.js
用户47949283569155 小时前
React Hooks 的“天条”:为啥绝对不能写在 if 语句里?
前端·react.js
我命由我123455 小时前
SVG - SVG 引入(SVG 概述、SVG 基本使用、SVG 使用 CSS、SVG 使用 JavaScript、SVG 实例实操)
开发语言·前端·javascript·css·学习·ecmascript·学习方法
用户47949283569156 小时前
给客户做私有化部署,我是如何优雅搞定 NPM 依赖管理的?
前端·后端·程序员
C_心欲无痕6 小时前
vue3 - markRaw标记为非响应式对象
前端·javascript·vue.js
qingyun9896 小时前
深度优先遍历:JavaScript递归查找树形数据结构中的节点标签
前端·javascript·数据结构