当前位置:首页 » 《关于电脑》 » 正文

前端webWorker 的介绍以及应用

5 人参与  2024年11月26日 10:00  分类 : 《关于电脑》  评论

点击全文阅读


文章目录

webWorker以下是关于 Web Workers 的一些关键概念:控制台查看使用注意事项消息传递创建subworkerwebWorker的具体使用注意事项 共享worker(SharedWorker)创建方法:与专用worker的主要区别:

webWorker

JavaScript是单线程的语言,如果在浏览器中需要执行一些大数据量的计算,页面上的其他操作就会因为来不及响应而出现卡顿的情况,因为这时js还在帮你完成上一个指令呢!这对用户体验来说是极其糟糕的。拿BIM数据的轻量化展示来说,在浏览器端展示大体量的模型,需要从约定的标准模型数据格式中先请求回来各种数据,然后解析计算各种顶点、颜色、属性数据等,在这段过程中前端页面就需要等待一段时间。

webWorker 使用场景:Web Worker 在处理一些耗时的计算、大量数据的处理和其他计算密集型任务方面表现出色,可以提高整体的性能和用户体验。但要注意,它们并不适用于所有的场景,特别是涉及到直接操作 DOM 的情况。

以下是关于 Web Workers 的一些关键概念:

线程模型: 在传统的浏览器中,JavaScript 是在主线程中运行的,而主线程主要负责处理用户界面和与用户交互的任务。使用 Web Workers 可以创建额外的线程,这些线程在后台运行,独立于主线程。独立的全局上下文: 每个 Web Worker 都有自己独立的全局上下文,与主线程中的全局上下文是分离的。这意味着在 Web Worker 中定义的变量和函数不会影响主线程中的环境,反之亦然。通信: 主线程和 Web Worker 之间通过消息进行通信。可以使用 postMessage 方法发送消息,并在两者之间建立双向通信。消息传递是通过拷贝而不是共享对象来完成的,确保数据的安全性。不能访问 DOM: Web Workers 不能直接访问 DOM,这意味着不能直接操作页面上的元素。它们主要用于处理计算密集型的任务,而不是用户界面的交互。网络请求: Web Workers 可以执行异步操作,包括发起网络请求。它们可以执行一些与网络相关的任务而不会阻塞主线程。生命周期: Web Workers 有自己的生命周期,可以通过事件监听器(如 onmessage 和 onerror)来捕获相关事件。当不再需要一个 Web Worker 时,可以通过调用 terminate 方法来终止它。限制: 由于 Web Workers 在独立的线程中运行,因此它们不能直接访问主线程的变量和函数。通信是通过消息传递实现的,这也导致了一些数据的复制开销。

控制台查看

在这里插入图片描述

使用注意事项

同源限制:worker脚本与主进程的脚本必须遵守同源限制。他们所在的路径协议、域名、端口号三者需要相同

接口限制:window作用域下的部分方法不可使用,如DOM对象、window.alert和window.confirm等方法。可使用参考 Supported Web APIs

文件限制:无法加载本地js文件,必须使用线上。

记得关闭:worker会占用一定的系统资源,在相关的功能执行完之后,一定要记得关闭worker。
父进程中使用:worker.terminate(); 关闭;
在worker进程内部关闭 self.close();

消息传递

主进程和worker之间通过发送消息的机制进行通信。对于主进程和worker自身:

都使用postMessage发送消息都使用onmessage接收消息都使用onerror监听错误事件

在主进程中onmessage、onerror和postMessage 必须挂在worker对象上。在worker中使用时
self.onmessage \self.postMessage\ self.onerror就行,或者不写self,因为在worker内部,self指向worker自己

创建subworker

在一个worker中创建多个子worker分别处理不同的内容
注意:子worker与父worker同样需要遵守同源限制。
在这里插入图片描述

webWorker的具体使用

在这里插入图片描述

页面

<script lang="ts" setup>import BackButton from '/@/components/BackButton/index.vue';import { onMounted, reactive, watch } from 'vue';const props = defineProps({  value: {    type: String,    default: '',  },});onMounted(() => {});var worker = new Worker('worker.js');// 向 Worker 发送消息worker.postMessage(100); // 传递数据,例如计算斐波那契数列的第 30 项// 监听从 Worker 返回的消息worker.onmessage = function (event) {  var result = event.data;  console.log('Worker 返回的结果1:', result);  // 关闭 Worker  worker.terminate();};// 监听 Worker 的错误信息worker.onerror = function (error) {  console.error('Worker 发生错误:', error);};/** * 开多个线程 */var worker2 = new Worker('worker2.js');worker2.postMessage(10); // 传递数据,例如计算斐波那契数列的第 30 项// 监听从 Worker 返回的消息worker2.onmessage = function (event) {  var result = event.data;  console.log('Worker 返回的结果2:', result);  // 关闭 Worker  worker.terminate();};// 监听 Worker 的错误信息worker2.onerror = function (error) {  console.error('Worker 发生错误:', error);};</script><template>  <br />  <div class="m-10">    <div class="flex-start">      <BackButton />    </div>    <h1>test webworker</h1>  </div></template><style lang="less" scoped></style>

worker.js

self.onmessage = function (event) {    console.log(event);    let data = event.data    // 计算处理大数据量的逻辑    let result = fn(data)    // 将结果发送回主线程    self.postMessage(result)}// 大数据量的逻辑function fn(n) {    let result = 0    for (let i = 0; i <= n; i++) {        result += i    }    return result}

注意事项

注意:worker.js 最好放到public文件夹下,否则打包后可能找不到文件
worker.postMessage(dade),这里如果data内容过多或者结构复杂传不过去(有报错),我临时想一个方法:JSON.stringify(data)转换成字符串,在worker.js中接受用JSON.parse(event.data),还有如果用.ts报错,那就js,这些是我实际用的时候遇到的问题

下面的图片你仔细看其实就是将 [{},{}] 的数据格式转换成二维数组的格式,但是由于这里有几十万条数据,特别多,处理起来就造成的主线程的卡顿,所有就多开了一个线程;

在这里插入图片描述

共享worker(SharedWorker)

上面创建worker的方式在MDN中被归类为专用worker的用法。另一类worker是共享worker,其实际用途与专用worker差异并不大,对于一些公用的方法可以放在共享Worker中供不用的场景使用。SharedWorker可以:

在不同的html页面之间使用共享worker;在主窗口和iframe之间使用共享worker;不同的worker同时访问共享worker中定义的数据或方法;

创建方法:

// 在同源的两个页面中都创建SharedWorker,使用同一个脚本var myWorker = new SharedWorker("xxx.js");

与专用worker的主要区别:

在共享worker的使用环境下,主进程和worker的监听和发送消息都要在port端口下进行

myWorker.port.postMessage([first.value, second.value]);

共享worker端口启动后时,两个页面的主进程都会向 worker 发送消息。在worker中使用事件监听需要放在onconnect事件中进行

onconnect = function(e) {  var port = e.ports[0];  port.onmessage = function(e) {    var workerResult = 'Result: ' + (e.data[0] * e.data[1]);    port.postMessage(workerResult);  }  port.start();}

如果使用 addEventListener 方式监听 worker消息事件,需要在主进程中使用myWorker.port.start()方法主动启动端口,使用onmessage监听则不用调用启动的方法。

myWorker.port.addEventListener('message', function(e) {    // xxx    console.log('Message received from worker');});myWorker.port.start();

在onconnect中使用port.onmessage和port.postmessage进行监听和发送
主进程中使用 port.postMessage()和 port.onmessage 处理从 worker 返回的消息

eg:
在这里插入图片描述

注意开启服务

index.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>111</title></head><body>    <div><button id="add">add</button></div>    <h1 id="one">12</h1>    <!-- <iframe src="index2.html" style="width: 600px;height: 600px; border: 1px solid red;"></iframe> --></body></html><script>    let worker = new SharedWorker('sharedworker.js')    worker.port.postMessage(['first', 66])    worker.port.onmessage = function (e) {        console.log('接收到index页面的数据:' + e.data);        let one = document.querySelector('#one')        one.innerHTML = e.data[1]    }    //发送数据给sharedworker    document.querySelector("#add").onclick = function () {        let count = Number(document.getElementById('one').innerHTML)        count++        worker.port.postMessage(['one', count]);        document.querySelector('#one').innerHTML = count    };</script>

index2.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>222</title></head><body>    <h1 id="two">two</h1></body></html><script>    console.log(window.SharedWorker);    let worker = new SharedWorker('sharedworker.js')    worker.port.postMessage({ id: 'one' })    worker.port.onmessage = function (e) {        console.log('接收到index页面的数据:' + e.data);        let one = document.querySelector('#two')        one.innerHTML = e.data[1]    }</script>

sharedworker.js

var list = [];var list_id = [];onconnect = function (e) {    var port = e.ports[0];    port.addEventListener('message', function (e) {        console.log(e);        if (e.data.id) {            var index = list_id.indexOf(e.data.id);            console.log(index);            if (index === -1) {                list.push(port);                list_id.push(e.data.id);            } else {                //关闭上个链接                list[index].close();                list[index] = port;            };        }        else {            if (e.data[0] == 'first') {                port.postMessage(e.data)            } else {                send(e.data[1], e.data[0]);            }        };    });    port.start();}var send = function (data, id) {    var index = list_id.indexOf(id);    console.log(index);    if (index !== -1) {        list[index].postMessage([id, data]);    };};

点击全文阅读


本文链接:http://zhangshiyu.com/post/192146.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1