前言

在说Service Worker前有必要说一下Web Worker,因为Service Worker本身就属于Web Worker的延伸,大部分功能也是基于Web Worker进行的扩展。

背景

众所周知,JavaScript引擎是以单线程调度的方式进行,我们无法同时运行多个JavaScript文件,这种情况下就会导致对硬件资源无法充分利用,并且当在进行一些高耗性能的操作时,会影响主线程的其他任务,造成任务阻塞及用户体验差等问题。

在这种劣势情况下,到 2008 年 W3C 提出第一个 HTML5 草案开始,就在 HTML5 中提出了Web Worker的概念,并规范了Web Worker的三大特征:

  • 能够长时间运行
  • 理想的启动性能
  • 理想的内存消耗

简介

Web Worker 是HTML5标准的一部分,这一规范定义了一套 API。实现了 用Web Worker 来实现 JavaScript 的 “多线程” 技术,并发执行多个 JavaScript 脚本。

Web Worker 与传统多线程

每个JavaScript脚本执行流都称为一个线程,彼此之间互相独立,并且有浏览器中的 JavaScript 引擎负责管理,当然这并不是说JavaScript支持多线程,虽然传统JavaSript有多种方式实现了对多线程的模拟(例如:setinterval,setTimeout,以及一些异步的操作方法等),但是在本质上程序的运行仍然是由 JavaScript 引擎以单线程调度的方式运行的,而Web Worker的线程是依赖于浏览器(宿主环境)来实现的,从而实现了对浏览器端多线程编程的支持。

Web Worker 线程种类

Web Worker 有两种不同线程类型,分别是:

  • Dedicated Worker (专用线程)。只能被首次生成它的脚本使用
  • Shared Worker (共享线程)。可以同时被多个脚本使用

通常来说的Web Worker指的就是Dedicated Worker,Service Worker也属于其中,并且各大浏览器对其支持良好,而Shared Worker指的是SharedWorker,目前各大浏览器对其支持度较差。

这里主要对Dedicated Worker进行详细说明,对于Shared Worker不再进行细说。

Worker模式

Worker线程执行流

创建 Web Worker

下面说一下如何创建一个Web Worker

语法:

new Worker(in DOMString aStringURL
);

使用上面的方式即可以创建一个Web Worker对象,它执行的是aStringURL中的脚本。目前大多数浏览器是支持data URI的aStringURL的,可以通过URL.createObjectURL(blob)创建。但需要注意的是脚本必须遵循同源策略。

下面创建一个Worker,Worker的执行脚本是workerfile.js,创建成功后,它会返回一个新的Worker对象赋值给前面声明的workerObj变量

var workerObj = new Worker('./workerfile.js');

这里需要注意, worker线程的创建的是异步的,主线程代码不会阻塞在这里去等待worker线程去加载、执行相应的脚本文件,而是会立即向下执行后面代码。

Web Worker实例方法

Worker的实例方法只有两个:

  • postMessage
  • terminate

postMessage

主线程向生成的Worker线程发送数据的方法。

语法:

workerObj.postMessage(aMessage, transferList);
  • aMessage:向Worker线程发送的消息数据对象。它可以是任何类型的值或JavaScript对象。
  • transferList:可选。Transferable类型的数组。主要用在 ArrayBuffer, MessagePort, ImageBitmap对象。

注意:

postMessage发送的aMessage参数,在传递通讯的时候会对数据进行克隆,为了防止多个线程间的数据同时修改的问题。实际上,浏览器内部的实现是,先将通信传递的数据串行化,随后把串行化后的数据发给子线程,后者再将数据还原。

postMessage也可以以二进制的方式传输,例如 ArrayBuffer 、File、Blob、ImageBitmap等对象。但是往往传输的这些对象数据量都很大,前面说了传输数据会进行拷贝,如果传一个100MB的数据,那么浏览器默认会再复制一份100MB的数据,导致一些不必要的资源消耗。为了防止这种问题,就可以使用上面说的第二个参数transferList来解决。

顺道科普一下Transferable接口。这个接口代表一个能在不同可执行上下文中相互传递的对象,例如主线程和Worker线程。

var arrBuff = new ArrayBuffer(8);
myWorker.postMessage(arrBuff, [arrBuff]);

terminate

语法:

workerObj.terminate()

用于立即终止worker对象的行为,如果worker正在运行着任务也会立即终止。

Web Worker实例属性

Worker实例包含两个属性:

  • onmessage:用来接收worker线程传递过来的数据事件。
  • onerror:用来接收worker线程的错误信息。

onmessage

onmessage属性表示一个EventHandler事件处理函数,当Worker子线程返回一条消息时被调用。

语法:

workerObj.onmessage = function(e) { ...
}

传递来的消息被封装在事件的data属性中。

workerObj.onmessage = function(e) {var result = e.data;
}

onerror

onerror属性是EventListener 一个事件监听函数,一旦有类型为 error 的 ErrorEvent 从 worker线程中冒泡出来时就会执行该函数。可以通过preventDefault()来取消冒泡。

主要用到的错误属性有:

  • message: 可读的错误信息
  • filename: 发生错误的脚本文件名称
  • lineno: 发生错误的脚本所在文件的行数

Web Worker文件方法

Worker线程对象抽象于DedicatedWorkerGlobalScope接口。此作用域下没有window对象,需要用self来调用。

在发送数据和接收数据使用的方法和worker实例对象的一样:

  • postMessage
  • onerror

这两个方法就不说了,还有一个close方法说一下。

close

这个和terminate()有点类似。这个方法主要用来清除所有在WorkerGlobalScope事件环中的排队任务,关闭特定作用域。

self.close()

importScripts 导入脚本

WorkerGlobalScope 对象中可以使用importScripts()方法来进行对脚本文件和资源的引入。

但这个操作需要注意:

  • 如果没有给 importScripts 方法任何参数,那么立即返回,终止下面的步骤。
  • 解析 importScripts 方法的每一个参数。
  • 如果有任何失败或者错误,抛出 SYNTAX_ERR 异常。
  • 尝试从用户提供的 URL 资源位置处获取脚本资源。
  • 对于 importScripts 方法的每一个参数,按照用户的提供顺序,获取脚本资源后继续进行其它操作。

Worker线程声明周期

worker线程间的数据传递必须依赖于浏览器的context环境,通过MessagePort进行传递数据,所以每个worker线程的全局作用域都会有端口列表,并且会在WorkerGlobalScope中生成一个worker线程的线程列表,在初始化时为空。当worker线程创建时会被填充进去,当worker线程终止时会从这个列表删除。

worker线程中可调用的对象

在worker线程中,可以获得下列对象:

  • navigator
  • location
  • XMLHttpRequest
  • setTimeout/setInterval
  • Application Cache
  • fetch
  • atob/btoa

等等。

实例

下面写一个使用的小例子

html文件:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title>
</head>
<body>
<button id="btn">发送</button>
<script>var worker = new Worker('./worker.js')btn.onclick = function(){worker.postMessage({a:1,b:2,c:3})}worker.onmessage = function(e){console.log('index-msg:', e)}worker.onerror = function(e) {console.log('index-err', e)e.preventDefault()}
</script>
</body>
</html>

worker.js文件

self.onmessage = function(e) {console.log('worker in:', e)self.postMessage('get postMessage!')
}

兼容性

还是有必要列一下Worker目前在浏览器上的兼容性:

可以看到支持的非常不错。

总结

可以看到Web Worker的出现使得在 Web 进行多线程编程成为可能,对于高消耗、耗时长的操作可以放到woker里面去进行。

所以可以在以下应用场景使用:

  • 使用专用线程进行数学运算
  • 图像处理
  • 大量数据的检索
  • 背景数据分析

等。


博客名称:王乐平博客

CSDN博客地址:http://blog.csdn.net/lecepin

本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。

PWA(Progressive Web App)入门系列:(五)Web Worker相关推荐

  1. PWA(Progressive Web App)入门系列:(一)PWA简介

    前言 PWA做为一门Google推出的WEB端的新技术,好处不言而喻,但目前对于相关方面的知识不是很丰富,这里我推出一下这方面的入门教程系列,提供PWA方面学习. 什么是PWA PWA全称Progre ...

  2. PWA(Progressive Web App)入门系列:(三)PWA关键技术Manifest

    前言 前面说过,让Web App能够达到Native App外观体验的主要实现技术就是PWA中的manifest技术,本章会详细说明manifest的实现,及各个参数的具体含义,还将了解如何定义Web ...

  3. PWA(Progressive Web App)入门系列:安装 Web 应用

    前言 在传统的 Web 应用中,通常只能通过在浏览器的地址栏里输入相应的网址才能进行访问,或者把网页地址创建到桌面上通过点击,然后在浏览器里打开. 传统模式下,图标.启动画面.主题色.视图模式.屏幕方 ...

  4. PWA(Progressive Web App)入门系列:Sync 后台同步

    前言 当我们在一些地下停车场,或者在火车上.电梯等无法避免的信号不稳定的场所,使用网站应用处理一些表单操作或者上传数据的操作时,面临的将是网络连接错误的响应,使用户的操作白费. 而此刻 PWA 的 S ...

  5. PWA(Progressive Web App)入门系列:Cache Storage Cache

    前言 目前浏览器的存储机制有很多,如:indexedDB.localStorage.sessionStorage.File System API.applicationCache 等等,那为什么又制定 ...

  6. PWA(Progressive Web App)入门系列:(二)相关准备

    前言 在上一章中,对PWA的相关概念做了基本介绍,了解了PWA的组成及优势.为了能够更快的进入PWA的世界,这一章主要对在PWA开发中,需要注意的问题,运行的环境及调试工具做介绍说明. 浏览器要求 因 ...

  7. PWA(Progressive Web App)入门系列:Push

    前言 很多时候,原生应用会通过一些消息推送来唤起用户的关注,增加驻留率.网页该怎么做呢?有没有类似原生应用的推送机制?推送功能又能玩出什么花样呢? Push API Push API 给与了 Web ...

  8. PWA(Progressive Web App)入门系列:Notification

    前言 在很多场景下,需要一种通知的交互方式来提醒用户,传统方式下可以在页面实现一个 Dialog,或通过修改网页的 title 来实现消息的通知.然而传统的实现存在着一定的不足,在网页最小化的情况下, ...

  9. PWA(Progressive Web App)入门系列:Fetch Request Headers Response Body

    前言 在 WEB 中,对于网络请求一直使用的是 XMLHttpRequest API 来处理,XMLHttpRequest 也很强大,传统的 Ajax 也是基于此 API 的.那么为什么 W3C 标准 ...

最新文章

  1. win 2008 控制共享文件夹大小_Windows转Mac Win10局域网文件共享设置
  2. python多线程队列爬虫流程图_python 多线程爬虫 队列queue问题。
  3. 04,认证、权限、频率
  4. java super extends_Java继承和super的用法
  5. 一个成型的awt所必须的frame组件
  6. testlink配置修改
  7. css中hack是什么
  8. 12步让你的web1.0变成web2.0
  9. jQuery 5 条件选择器
  10. 安卓装Linux ,坑真的多,Linux deployTermux踩坑记||在旧手机上建立自己的服务器(1)||2020年新货
  11. DAVIS2016+Matlab+Win10使用指南
  12. 华为鸿蒙主机,华为发布全屋智能主机以及V系列智慧屏 搭载鸿蒙系统
  13. word中“项目符号”和后面的文字间隔太远
  14. java中的消息提示框
  15. Error starting userland proxy: listen tcp4 0.0.0.0:8005: bind: address alrea
  16. Open3D 曲面重建
  17. 产品全类目下找不到关键词,只有到特定类目才能找到,修改PRODUCT TYPE
  18. new和delete,malloc和free
  19. js将数字转换成大写汉字
  20. 数据软件分析(一)——静态分析

热门文章

  1. 解释spring,struts,hibernate优缺点
  2. 团队作业-第二周-测试计划
  3. 主流平台应用与游戏的编程语言/工具(图)
  4. 18款 非常实用 jquery幻灯片图片切换
  5. 2013年3月16日星期六
  6. 听小鹏讲废话之OSI
  7. ExtJs UI框架学习六
  8. css+沿正方形旋转,CSS3+SVG+JS 正方形沿着正方本中轴移动翻转的动画
  9. spark的流失计算模型_使用spark对sparkify的流失预测
  10. spring中@Inject和@Autowired的区别?分别在什么条件下使用呢?