web worker多线程的与js执行顺序的理解,web worker的实现

什么是webworker

  1. Web Worker 是一种在浏览器中运行 JavaScript 脚本的机制,它可以将运算密集型的任务放在另一个线程中运行,以避免阻塞浏览器主线程,从而提高页面的响应速度和用户体验。

  2. Web Worker 是 HTML5 引入的一项标准,它提供了一种在后台运行 JavaScript 脚本的方式,以避免阻塞浏览器的主线程。Web Worker 可以将计算密集型的任务放在另一个线程中运行,从而避免阻塞浏览器主线程,提高页面的响应速度和用户体验。

js执行顺序

  • js代码在执行的时候,会先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后,再将异步宏任务从队列中调入主线程执行,一直循环至所有的任务执行完毕(完成一次事件循环EventLoop)

  • 宏任务:整体代码script、setTimeout、setInterval、setImmediate、i/o操作(输入输出,比如读取文件操作、网络请求)、ui render(dom渲染,即更改代码重新渲染dom的过程)、异步ajax等

  • 微任务:Promise(then、catch、finally)、async/await、process.nextTick、Object.observe(⽤来实时监测js中对象的变化)、 MutationObserver(监听DOM树的变化)

setTimeout(function () {
 console.log('1');
})
new Promise(function (resolve) {
 console.log('2');
 resolve();
}).then(function () {
 console.log('3');
})
console.log('4');
//打印顺序 2 4 3 1

分析:
1、遇到setTimeout,异步宏任务将其放到宏任务列表中,命名为time1;

2、new Promise 在实例化过程中所执⾏的代码都是同步执⾏的( function 中的代码),输出2 ;
3、 将 Promise 中注册的回调函数放到微任务队列中,命名为 then1 ;
4、 执⾏同步任务 console.log(‘4’) ,输出 4 ,⾄此执⾏栈中的代码执⾏完毕;
5、 从微任务队列取出任务 then1 到主线程中,输出 3 ,⾄此微任务队列为空;
6、 从宏任务队列中取出任务 time1 到主线程中,输出 1 ,⾄此宏任务队列为空

web worker的使用

  1. npm install worker-loader 先下载依赖
    下面的配置在vue.config.js修改Webpack 的构建规则,
    表示将 Web Worker 脚本内联到打包后的 JavaScript 文件中,避免了额外的网络请求和文件加载时间。
  2. chainWebpack: config => {
    config.module
    .rule(‘worker-loader’)
    .test(/.worker.js$/)
    .use({
    loader: ‘worker-loader’,
    options: {
    inline: true
    }
    })
    .loader(‘worker-loader’)
    .end()
    }
使用

先在src目录下新建workers文件夹,接着在里面新建worker.js,在js文件里添加下面的测试代码


addEventListener("message", async (event) => {
  const result = await processData(event.data);

  postMessage(result);
});
function processData(item) {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
        resolve("3");
    }, 1000);
    
  });
}

在这里插入图片描述
然后在views底下建立一个.vue文件,去生成若干个web worker创建线程,配合promise.all可以等待加载结束,在worker.js里使用settimeout模拟,底下有一个2000可以自行修改,意思是生成几个web worker,我这里的是5个,可自行修改启用多条线程

<template>
  <div ></div>
</template>
<script>
import Worker from "worker-loader!@/workers/worker";

export default defineComponent({
  data() {
    return {
      worker: null,
    };
  },
  async created() {
    this.inquirewbWorker(); // 在组件创建时调用connect函数连接WebSocket
  },
  methods: {
    createWorker() {
      const worker = new Worker();
      worker.onmessage = function (e) {
        const { data } = e;
      };
      worker.onerror = function (error) {
        console.error("Web Worker 发生错误:", error);
      };
      return worker;
    },
    async sendData(worker, data) {
      worker.postMessage(data);
    },
    waitWorker(worker) {
      return new Promise(function (resolve, reject) {
        worker.onmessage = function (e) {
          const { data } = e;
          resolve(data);
        };
        worker.onerror = reject;
      });
    },
    processData(item) {
      return new Promise(function (resolve, reject) {
        setTimeout(() => {
          resolve("3");
        }, 1000);
      });
    },
    async inquirewbWorker() {
      const data = Array.from({ length: 10000 }, (_, i) => ({
        id: i,
        value: Math.random(),
      })); // 生成10000个随机数

      const fortime = new Date().getTime();
      var resultmap;
      data.map(async (item, i) => {
        resultmap = await this.processData(event.data);
        if (i === data.length - 1) {
          console.log("forEach结束时间", new Date().getTime() - fortime);
        }
      });
      // return
      const datalist = data;

      const numWorkers = Math.ceil(datalist.length / 2000);
      const workers = Array.from({ length: numWorkers }, () =>
        this.createWorker()
      ); // 创建 Web Worker 数组
      console.log("numWorkers", numWorkers);
      for (let i = 0; i < numWorkers; i++) {
        const start = i * 2000;
        const end = Math.min(start + 2000, datalist.length);
        const dataChunk = datalist.slice(start, end);

        this.sendData(workers[i], dataChunk);
      }
      const wbtime = new Date().getTime();

      const results = await Promise.all(workers.map(this.waitWorker)); // 等待所有 Web Worker 完成
      console.log("所有 Web Worker 完成:", new Date().getTime() - wbtime);
    },
  },
});
</script>
<style lang="scss" scoped>
.mapbox {
  margin-bottom: 50px;
}
</style>


在页面中可以看到线程的数量,一万条数据量较少,差距可能不大,web worker需要计算量很大的数据才能看到明显区别,不然不建议进行使用,1W条数据差距大概在1秒,那么十万就是10秒,并且webworker可以开启多个线程优势
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

webworker跟异步的区别

这两个其实不是一个东西,上面提到js执行顺序的基础只是为方便理解。

  1. js是单线程
  2. webworker是可以支配多线程
    通俗点讲
  • 在js里用多个异步,注意js是单线程,类似于A去上班,路上买包子,发现包子没做好,直接先去上班,等打卡后再来取,
  • webworker多线程,类似于A去上班,路上买包子,发现包子没做好,叫了个跑腿在那等,自已先去上班,等跑腿拿到了后,再送过来给A(相等于创建一个子线程,子线程完成合入到主线程)
  1. 执行环境不同:

异步是一种编程模式,可在单线程环境中使用,适用于任何情况下的异步操作。
Web Worker是在浏览器环境中特有的技术,用于在独立的线程中执行计算密集型任务,适用于大量计算但不影响主线程的情况。

  1. 使用方式不同:
    异步编程可以通过回调函数、Promise、async/await等方式实现。
    Web Worker需要通过脚本文件创建,并通过消息传递机制与主线程通信。

  2. 功能和用途不同:
    异步编程用于解决长时间操作的阻塞问题,提高程序的响应性能和吞吐量。
    Web Worker用于后台执行复杂的计算任务,不阻塞页面的渲染和用户交互。

webworker的优缺点
  • 优点
    1. 多线程执行: Web Worker在独立的线程中执行,不会阻塞主线程,可以充分利用多核处理器和系统资源,提高性能和响应速度。
    后台计算任务: Web Worker适用于执行复杂的计算任务,可以在后台处理大量的数据计算、图像处理、数值模拟等操作,而不会干扰页面的渲染和用户交互。
    消息传递机制: Web Worker与主线程之间通过消息传递机制进行通信,可以实现高效的数据交换和共享,便于处理异步任务和传递大量的数据。
    提升用户体验: 通过将耗时的计算任务放在Web Worker中执行,可以提高页面的响应速度和流畅度,改善用户体验。
  • 缺点:
    无法操作DOM: Web Worker运行在与主线程分离的上下文中,无法直接操作DOM元素,因此不能通过Web Worker直接更新页面内容或响应用户交互。
    文件加载限制: Web Worker在浏览器中作为独立的脚本文件加载,并受到同源策略的限制,必须与主线程的代码来自相同的域名下。
    较高的内存消耗: 每个Web Worker都需要一定的资源和内存来维护,创建大量的Web Worker可能会占用大量的内存,对于资源有限的设备可能会造成性能问题。
    复杂性和调试困难: 使用Web Worker需要编写额外的代码来管理消息传递和同步问题,增加了代码的复杂性,并且在调试时可能会出现一些困难。
webworker使用场景
  1. 大量请求:有限制,因为会受到跨域影响,需要在同个域进行,也无法通过jsonp来解决
  2. webworker没有dom跟window对象,目前大部分的第三方插件都会带有window对象,出现即报错
  3. 内部可以使用self访问webworker
  4. 复杂计算任务: Web Worker适用于执行复杂的计算任务,如大量数据的处理、图像处理、数值模拟等。通过将这些计算任务放在Web Worker中执行,可以充分利用多核处理器和系统资源,提高性能和响应速度。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3支持Web Worker多线程的特性,这是一种在浏览器中运行JavaScript代码的方式,可以在后台运行独立的线程,提高应用程序性能和响应能力。 在Vue 3中,可以使用`Vue. createApp()`方法创建Vue实例,并使用`createWebWorker`方法将其转换为Web Worker。这个方法接收一个参数,指定Worker脚本的URL或者内联函数的URL。例如: ```javascript const app = Vue.createApp({...}); const worker = app.createWebWorker('path-to-worker-script.js'); ``` 然后,可以使用`worker`对象的方法与Web Worker进行通信。例如,通过`postMessage`方法发送消息给Worker线程: ```javascript worker.postMessage({ data: 'message' }); ``` 同时,还可以通过`onmessage`事件监听来自Worker线程的消息: ```javascript worker.onmessage = function(event) { const data = event.data; // 处理接收到的消息 }; ``` 在Worker线程中,可以使用`self`关键字引用Worker对象,同样可以通过`postMessage`方法发送消息给主线程,并通过`onmessage`事件处理来自主线程的消息。 Web Worker多线程功能可以极大地提高Vue应用程序的性能和响应能力,将一些耗时的操作(如计算、渲染等)放在Worker线程中运行,避免阻塞主线程,提高用户体验。 需要注意的是,在使用Web Worker时,需要考虑到跨域访问的限制,以及数据传输的序列化和反序列化等问题。在实际应用中,需要根据具体需求和场景合理使用Web Worker多线程功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值