宁睿 发表于 2024-6-14 18:05:44

前端webWorker 的先容以及应用

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 在独立的线程中运行,因此它们不能直接访问主线程的变量和函数。通信是通过消息通报实现的,这也导致了一些数据的复制开销。
控制台检察

https://img-blog.csdnimg.cn/direct/3187160c633642ae9e8807fb3568951f.png
利用注意事项



[*] 同源限定: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同样必要遵守同源限定。
https://img-blog.csdnimg.cn/direct/a01e4d41b9a64941bc85a70f6ac2f108.png
webWorker的具体利用

https://img-blog.csdnimg.cn/direct/108c541fc0e74668ae41312b630e9c0b.png
页面
<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,这些是我实际用的时候遇到的题目
下面的图片你细致看其实就是将 [{},{}] 的数据格式转换成二维数组的格式,但是由于这里有几十万条数据,特殊多,处理起来就造成的主线程的卡顿,全部就多开了一个线程;
https://img-blog.csdnimg.cn/direct/ccc28a63f09147a481080230576a9187.png
共享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();
共享worker端口启动后时,两个页面的主历程都会向 worker 发送消息。在worker中利用事件监听必要放在onconnect事件中举行
onconnect = function(e) {
var port = e.ports;

port.onmessage = function(e) {
    var workerResult = 'Result: ' + (e.data * e.data);
    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:
https://img-blog.csdnimg.cn/direct/372a3eced9c241adac1e991b5d1b24b6.png
注意开启服务
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
    }
    //发送数据给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
    }

</script>
sharedworker.js
var list = [];
var list_id = [];
onconnect = function (e) {
    var port = e.ports;
    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.close();
                list = port;
            };
      }
      else {
            if (e.data == 'first') {
                port.postMessage(e.data)
            } else {
                send(e.data, e.data);
            }
      };
    });
    port.start();
}
var send = function (data, id) {
    var index = list_id.indexOf(id);
    console.log(index);
    if (index !== -1) {
      list.postMessage();
    };

};

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 前端webWorker 的先容以及应用