本文讲述内容如下所示:

  1. Web Worker概述
  2. API
  3. Web Worker在实际项目中应用
  4. 总结

一、Web Worker概述

1、Web Worker产生背景

众所周知JavaScript是单线程的语言,所有任务只能在一个线程上完成,一次只能做一件事,即前面的任务还没有完成,后面的任务只能排队等待。如果前面的任务需要执行一些大数据量的计算,页面就会出现卡顿、点击无反应、甚至页面崩溃等现象。这对用户体验而言是非常糟糕的。

在这种情况下,Web Worker可以为js提供一个多线程环境 ,主线程可以将一些耗时、复杂的计算任务分配给Worker线程 ,两者可以同时运行,互不干扰,等到Worker线程任务完成后,再把结果发送给主线程。这样Worker线程负责耗时、复杂的计算任务,主线程主要负责界面渲染不会被阻塞,使得用户体验更流畅。

2、在浏览器控制台下,直观认识Web Worker

如下图所示,打开浏览器的控制台,点击Source项,看到小齿轮的文件,就是在项目中使用Worker做一些复杂、耗时的任务

3、使用 Web Worker注意项

1)同源限制:分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源;

2)DOM限制:Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用documentwindowparent这些对象,及其这些对象的属性和方法,比如alert、confirm等,但Worker 线程可以使用navigator对象和location对象;

3)通信联系:Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成

4、Web Worker浏览器支持程度

二、API

1、主线程

在主线程里面通过new 一个Worker线程对象,用来在主线程操作Worker。Worker线程对象的属性和方法如下:

1、Worker.onerror:指定 error 事件的监听函数。
2、Worker.onmessage:指定 message 事件的监听函数,发送过来的数据在Event.data属性中。
3、Worker.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
4、Worker.postMessage():向 Worker 线程发送消息。
5、Worker.terminate():立即终止 Worker 线程

2、worker线程

Web Worker 有自己的全局对象,不同于window对象,而是一个专门为 Worker 定制的全局对象,因此定义在window上面的对象和方法,在Web Worker 内不是全部都可以使用的。Worker 线程有一些自己的全局属性和方法:

self指向产生的这个worker线程,可不用书写self

1、self.name: Worker 的名字。该属性只读,由构造函数指定。
2、self.onmessage:指定message事件的监听函数。
3、self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
4、self.close():关闭 Worker 线程。
5、self.postMessage():向产生这个 Worker 线程发送消息。
6、self.importScripts():加载 JS 脚本

三、Web Worker在实际项目中的应用

1、使用Web Worker背景

前端调后台接口获取源数据,如下图所示,接口返回数据整体用时1.15s,数据量1.5MB,这时候前端需要对返回的1.5MB数据进行处理,如果这个处理直接放在主线程的话,会造成页面卡顿、点击无反应、甚至页面崩溃等问题。因此我们需要将这部分数据处理逻辑放在另一个线程中处理,避免干扰主线程。

 2、在webpack中配置Web Worker

插件worker-loader可以将js脚本注册为Web Worker

1)在项目中安装插件worker-loader

npm i worker-loader -D

2)在webpack的module.rules中配置以下规则

{test: /\.worker\.js$/, // 以.worker.js结尾的文件将被worker-loader加载loader: 'worker-loader',options: {inline: true, // 将 worker作为blob进行内联;内联模式将额外为浏览器创建chunk,即使对于不支持内联worker的浏览器也是这样的publicPath: assetsPublicPath   // 资源路径前缀}}

3)新建a.worker.js文件---该文件定义了worker对象线程要处理的任务,onmessage可接收主线程创建的worker对象线程发送的消息,postMessage()可向主线程的worker对象线程发送消息

onmessage = function (evt) {// 工作线程收到消息,传送的数据放在evt.data属性中var { arr, type, expand } = evt.datavar departmentTreeIdArr// 根据不同的行为做相应的事件处理if (type === 'initData') {// 从接口拿到数据后,需要初始化结构departmentTreeIdArr = getDepts(arr, expand)} else if (type === 'choose') {// 去重departmentTreeIdArr = removeRepeatData(arr)}// 事件处理完之后,向主线程的worker对象线程发送消息,返回处理后的结果postMessage({departmentTreeIdArr,type})
}function getDepts(arr, expand) {// toDo something// egs.return arr
}function removeRepeatData(arr) {// to do something// egs.return arr
}

4)在需要引进worker的vue文件中,引进a.worker.js文件,生成worker对象,向工作线程发送消息,并监听工作线程发送的信息

a. 引进a.worker.js文件:

<script>import Worker from './a.worker.js' // 引进worker文件...
</script>

b. 在mounted里面创建worker对象

<script>
import Worker from './a.worker.js' // 引进worker文件
export default {data: () => {return {worker: null // 保存worker对象}},mounted() {this.worker = new Worker() // 生成worker对象}
}
</script>

c. getDepartments方法调后台接口获取源数据,并通过worker.postMessage方法将源数据传给worker进行处理

<script>
import Worker from './a.worker.js' // 引进worker文件
export default {data: () => {return {worker: null // 保存worker对象}},mounted() {this.worker = new Worker() // 生成worker对象this.getDepartments() // 调接口获取源数据},methods: {getDepartments() {let url = '接口路径' this.$rootStore.state.loading.status = truethis.http(url).get().then((res) => {// res的数据达到2万多条,所以放worker处理,要不然页面会被卡死 this.worker.postMessage({ // 通过worker的postMessage方法将数据发送给worker进行处理arr: res, type: 'initData', expand: this.expand }) }) }}
}

d. 在mounted中监听worker向主线程发送处理完数据之后的消息

<script>
import Worker from './a.worker.js' // 引进worker文件
export default {data: () => {return {worker: null // 保存worker对象}},mounted() {this.worker = new Worker() // 生成worker对象this.getDepartments() // 调接口获取源数据this.worker.addEventListener('message', function (event) { // 监听message事件let {departmentTreeIdArr, type} = event.data // worker处理完后发送回来的数据在event.data中if (type === 'initData') { vm.dataTree = departmentTreeIdArr } else if (type === 'choose') {vm.$emit('on-choose-more-department', departmentTreeIdArr) } })}},methods: {getDepartments() {let url = '接口路径' this.$rootStore.state.loading.status = truethis.http(url).get().then((res) => {// res的数据达到2万多条,所以放worker处理,要不然页面会被卡死 this.worker.postMessage({ // 将数据发送给worker进行处理arr: res, type: 'initData', expand: this.expand }) }) }}
}
</script>

至此,在项目中使用Web Worker的流程就说完了

四、总结

当项目中有遇到大量数据处理的场景时候,可使用Web Worker来创建Worker子线程,在Worker子线程内进行运算,处理完后的结果再返回给主线程,避免主线程被阻塞,导致界面卡顿、崩溃等现象。

参考文章:

1、https://www.ruanyifeng.com/blog/2018/07/web-worker.html

2、https://blog.csdn.net/terrychinaz/article/details/115176725

3、https://webpack.html.cn/loaders/worker-loader.html

4、https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers

浅析Web Worker及实践相关推荐

  1. 2023 年的 Web Worker 项目实践

    前言 Web Workers 是 2009 年就已经提案的老技术,但是在很多项目中的应用相对较少,常见一些文章讨论如何写 demo ,但很少有工程化和项目级别的实践,本文会结合 Web Workers ...

  2. Web Worker 简介

    Web Worker 简介 为什么使用? JS 是单线程,现在计算机很多都是多核CPU,不能很好利用多核的性能.所以 web worker 就是在主线程外,再增加一个线程,进行高性能计算和高延迟任务. ...

  3. 一文搞懂 Web Worker(原理到实践)

    作者:poetry 原文地址:https://mp.weixin.qq.com/s/XF7qOhbBtYlwADCiyxbT-w Web Worker 作为浏览器多线程技术,在页面内容不断丰富,功能日 ...

  4. Web Worker 初探

    (给前端大全加星标,提升前端技能) 作者:SHERlocked93 juejin.im/post/5b4af72ae51d45198d4b1388 以前我们总说,JS是单线程没有多线程,当JS在页面中 ...

  5. 中国婚博会PHP高级工程师、安全顾问汤青松:浅析Web安全编程

    11月18号,2017看雪安全开发者峰会在北京悠唐皇冠假日酒店举行.来自全国各地的开发人员.网络安全爱好者及相应领域顶尖专家,在2017看雪安全开发者峰会汇聚一堂,只为这场"安全与开发&qu ...

  6. 关于Web Worker你必须知道的7件事

    原文:http://www.developer.com/lang/jscript/7-things-you-need-to-know-about-web-workers.html 译者: Rock(r ...

  7. 基于blob对象动态封装一个web worker

    一.前言   在html5出来以后,有许多新特性值得我们关注, 其中一个就是web worker.相信如果关心前端发展的同学就算没有使用过web worker也听过这个东西.今天我们就来讲一讲web ...

  8. 深入理解javascript异步编程障眼法h5 web worker实现多线程

    0.从一道题说起 var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert('end'); 1 2 3 4 ...

  9. 什么是Web Worker?

    简单点说,Web Worker就是一个运行在后台的JavaScript线程,不会影响页面的响应. 我们知道,JavaScript是单线程的脚本语言,即同一时刻只能做一件事情,否则会带来极其复杂的同步问 ...

最新文章

  1. 【组队学习】【32期】算法的应用
  2. 关于/etc/fstab
  3. 2010年第一届蓝桥杯省赛 —— 第一题
  4. 单片机串口发送数据很慢?这种方法帮助你提高!
  5. Centos7安装apt-get 在centos下用yum install xxx        不是使用apt-get
  6. [转载]抓大放小,要事为先
  7. android开发之 Gson 解析json数组
  8. VMware虚拟机克隆CentOS6.5后修改网卡
  9. spyder替换_Spyder 快捷键大全
  10. Spring with Hibernate persistence and transactions
  11. 【杂文】【IDEA】IDEA项目设置为maven并运行
  12. 华为机试HJ93:数组分组
  13. html5swf小游戏源码,FLASH打方块小游戏及as3代码
  14. 一元线性回归(Python)
  15. 如何自学html5 web前端工程师培训视频教程
  16. 2021vue面试题+答案
  17. 【随机过程】课后作业 1-条件概率期望密度
  18. 敏捷实践 | 如何正确使用故事点预估工作量?
  19. 前进路上,我们都曾经迷失
  20. Processing 案例 | 郭锐文先生的 worms

热门文章

  1. 《前端》炎黄盈动BPM
  2. 2分钟学会物联网平台协议解析——实践类
  3. 【Tableau】快速笔记
  4. 《Visual C# 程序设计》课程学习(9)——第9章 C# 2005 泛型编程
  5. 如何把微信语音汇总成一个MP3文件?
  6. 在apple developer APP上注册显示您的注册已被暂停解决办法
  7. 【PCL自学:Feature5】视点特征直方图VFH概念及使用 (持续更新)
  8. C++ 指针p1 p2,p1-p2 与*p1-*p2的区别
  9. 阿里云挖矿./trace -r 2 -R 2 --keepalive --no-color --donate-level 1 --max-cpu-usage 10
  10. **关于本人在使用JDBC时出现数据库连接失败问题**