整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

HTML5之多线程(Web Worker)

HTML5之多线程(Web Worker)

到 HTML5 总是让人津津乐道,太多的特性和有趣的 API 让人耳目一新。

但是很多童鞋还停留在语义化的阶段,忽视了 HTML5 的强劲之处

这节我们来探讨一下多线程 Web Worker。

一、明确 JavaScript 是单线程

JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。

听起来有些匪夷所思,为什么不设计成多线程提高效率呢?我们可以假设一种场景:

假定 JavaScript 同时有两个线程,一个线程在某个 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准

作为浏览器脚本语言,JavaScript 的主要用途是与用户互动,以及操作 DOM。

这决定了它只能是单线程,否则会带来很复杂的同步问题。

为了避免复杂性,从一诞生,JavaScript 就是单线程,这已经成了这门语言的核心特征,估计短期内很难改变。

二、新曙光:Web Worker

单线程始终是一个痛点,为了利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程。

但是子线程完全受主线程控制,且不得操作 DOM。

所以,这个新标准并没有改变 JavaScript 单线程的本质。

Web Workers 是现代浏览器提供的一个 JavaScript 多线程解决方案,我们可以找到很多使用场景:

1.我们可以用 Web Worker 做一些大计算量的操作

2.可以实现轮询,改变某些状态;

3.页头消息状态更新,比如页头的消息个数通知;

4.高频用户交互,拼写检查,譬如:根据用户的输入习惯、历史记录以及缓存等信息来协助用户完成输入的纠错、校正功能等

5.加密:加密有时候会非常地耗时,特别是如果当你需要经常加密很多数据的时候(比如,发往服务器前加密数据)。

6.预取数据:为了优化网站或者网络应用及提升数据加载时间,你可以使用 Workers 来提前加载部分数据以备不时之需。

加密是一个使用 Web Worker 的绝佳场景,因为它并不需要访问 DOM 或者利用其它魔法,它只是纯粹使用算法进行计算而已。

随着大众对个人敏感数据的日益重视,信息安全和加密也成为重中之重。这可以从近期的 12306 用户数据泄露事件中体现出来。

一旦在 Worker 进行计算,它对于用户来说是无缝地且不会影响到用户体验。

三、兼容性

四、基本概念

1.首先记得去判断是否支持

2.创建一个新的 worker 很简单

postMessage() 方法和 onmessage 事件处理函数是 Workers 的黑魔法。

3.postMessage 用来发送消息,而 onmessage 用来监听消息

在主线程中使用时,onmessage 和 postMessage() 必须挂在 worker 对象上,而在 worker中使用时不用这样做。

原因是,在 worker 内部,worker 是有效的全局作用域

4.异常处理:

5.终止 worker

worker 线程会被立即杀死,不会有任何机会让它完成自己的操作或清理工作。

6.在 worker 线程中,workers 也可以调用自己的 close 方法进行关闭:

五、快速开始

为了快速掌握,我们来做一个小例子:项目结构如下

Html

main.js

Work.js

代码很简单,主线程发送:「写的真好!」

web worker 收到消息,发现内容中含有「好」字,回传给主线程:「谢谢支持」

六、局限性

1.在 worker 内,不能直接操作 DOM 节点,也不能使用 window 对象的默认方法和属性

然而我们可以使用大量 window 对象之下的东西,包括 WebSockets,IndexedDB 以及 FireFox OS 专用的 Data Store API 等数据存储机制。

这里举个例子,我们修改 main.js:

再来修改 work.js

这时候运行就会报出:

这是因为:worker.js 执行的上下文,与主页面 HTML 执行时的上下文并不相同,最顶层的对象并不是 Window,woker.js 执行的全局上下文,而是 WorkerGlobalScope,下文我们具体说明。

2.workers 和主线程间的数据传递通过这样的消息机制进行:

双方都使用 postMessage() 方法发送各自的消息,使用 onmessage 事件处理函数来响应消息(消息被包含在 Message 事件的 data 属性中)。

这个过程中数据并不是被共享而是被复制。

3.同源限制

分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源

4.文件限制

Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自服务器

5.不允许本地文件

Uncaught SecurityError: Failed to create a worker:

script at '(path)/worker.js'

cannot be accessed from origin 'null'.

Chrome doesn’t let you load web workers when running scripts from a local file.

那如何解决呢?我们可以启动一个本地服务器,建议使用 http-server,简单易用。

6.内容安全策略

有别于创建它的 document 对象,worker 有它自己的执行上下文。

因此普遍来说,worker 并不受限于创建它的document(或者父级 worker )的内容安全策略。

我们来举个例子,假设一个 document 有如下头部声明:

Content-Security-Policy: script-src 'self'

这个声明有一部分作用在于,禁止它内部包含的脚本代码使用 eval() 方法。然而,如果脚本代码创建了一个 worker,在 worker 上下文中执行的代码却是可以使用 eval() 的。

为了给 worker 指定 CSP,必须为发送 worker 代码的请求本身加上一个 CSP。

关于 CSP(Content security policy 内容安全策略),可以看我之前的这篇文章Web 安全之 CSP(Content Security Policy)。

有一个例外情况,即 worker 脚本的源如果是一个全局性的唯一的标识符(例如,它的 URL 指定了数据模式或者 blob),worker则会继承创建它的 document 或者 worker 的 CSP。

七、扩展:WorkerGlobalScope

关于 ,我们可以在 MDN 上面找到文档:

1.self:

我们可以使用 WorkerGlobalScope 的 self 属性来获取这个对象本身的引用。

2.location:

location 属性返回当线程被创建出来的时候与之关联的 WorkerLocation 对象,它表示用于初始化这个工作线程的脚步资源的绝对 URL,即使页面被多次重定向后,这个 URL 资源位置也不会改变。

3.close:

关闭当前线程,与 terminate 作用类似。

4.caches:

当前上下文得 CacheStorage,确保离线可用,同时可以自定义请求的响应。

5.console:

支持 console 语法。

6.importScripts

我们可以通过 importScripts() 方法通过 url 在 worker 中加载库函数。

7.XMLHttpRequest

有了它,才能发出 Ajax 请求。

8.可以使用:

  • setTimeout/setInterval
  • addEventListener/postMessage

还有很多 API 可以使用,这里就不一一举例了。

八、异常处理

当 worker 出现运行中错误时,它的 onerror 事件处理函数会被调用。它会收到一个扩展了 ErrorEvent 接口的名为 error 的事件。

该事件不会冒泡并且可以被取消。

为了防止触发默认动作,worker 可以调用错误事件的 preventDefault() 方法。

错误事件我们常用如下这三个关键信息:

  • Message:可读性良好的错误消息;
  • Filename:发生错误的脚本文件名;
  • Lineno:发生错误时所在脚本文件的行号;

九、参考文章

1.JavaScript 运行机制详解:再谈Event Loop

2.MDN Web worker

3.从webWorker到serviceWorker

4.浅谈webWorker

十、热门原创文章

1.HTML5 之地理定位(Geolocation)

2.Git 版本控制之 Git-Flow

3.你了解软件测试吗?

eb worker是一个在后台运行的JavaScript程序,它不会影响当前页面的用户操作。 从事过Windows桌面编程的人,应该熟悉工作线程(Work Thread)的概念,该线程主要负责比较耗费时间的数据处理或通信方面的任务,当任务处理完成时,发送消息通知界面主线程(UI Thread)。 这样的多线程机制可以大大提高应用程序处理数据的能力,我们在前言中说过HTML5的设计目的之一就是想尽可能结合传统本地应用和网页之间的优点,Web Worker就是这样一个例子。文章最后给出了demo的访问网址。

Web Worker的好处

和C++(版本>=11)以及Go这些系统级语言内置支持多线程并行计算不同,网页JavaScript脚本只支持单线程,如果在HTML页面中执行脚本,那么该页面将不能响应用户交互,直到脚本执行完成。 那么如果不幸该脚本在等待某个网络数据包或者正在执行一个大的循环处理,页面就将处于僵死状态。

Web Workers 是HTML5提供的一个JavaScript多线程解决方案。通过使用Web worker,执行任务交付给浏览器在后台默默运行,而不会影响当前页面的性能,用户可以继续任何其他操作,这将大大提升用户体验。

浏览器支持

下面表格中的数字表示最早支持的版本号:

使用示例

下面的例子演示了一个计数的网页工作线程:

Step 1: 检查浏览器支持

并非所有浏览器都支持该API,因此在创建Web worker之前,我们需要先检测该特性是否被用户浏览器所支持:

Step 2: 创建一个Web Worker文件

我们新建一个外部JavaScript文件,文件名为"demo_workers.js",代码如下(简单的计数):

上述代码中的postMessage方法很重要,依赖于该方法,工作线程才能和HTML页面(用户界面)之间通信,该方法发送一个消息回给页面。

Step 3:创建一个Web Worker对象

我们已经有了上述的web worker文件,现在我们需要从HTML页面调用它。下面这行代码检查worker是否已存在,如果不存在,则创建一个新的Web Worker对象,并运行"demo_workers.js"文件中的代码:

然后我们可以在Web worker中发送和接收消息。我们给该Web worker添加一个"onmessage"事件侦听器。

当web worker发回一个消息时,页面事件侦听器中的代码被执行。web worker发回的数据被保存在event.data中。

Step 4:终止Web Worker

当一个Web worker对象被创建后,它将持续侦听消息(即使外部脚本已经执行完成),除非被终止。要终止一个web worker,释放相关的浏览器/计算机资源,使用 terminate() 方法:

w.terminate();

Step 5:重用Web Worker

如果您在worker被终止后,将worker变量设置为未定义(undefined),就可以被重用:

w=undefined;

完整的示例代码

Web worker的代码在外部.js文件中,HTML页面的代码如下:

Demo源码可访问:http://www.ikinsoft.com/3ddemo/webWork.html

下是针对高级前端工程师的HTML相关面试题:

问题1: 请解释HTML5的Web Storage API及其使用场景。

  • 考点: HTML5存储技术。
  • 答案: HTML5的Web Storage API提供了两种存储方式:sessionStorage和localStorage。它们用于在客户端存储数据,不依赖于服务器。sessionStorage存储的数据在浏览器会话结束时会自动清除,而localStorage存储的数据除非手动清除,否则会一直存在。这常用于存储用户设置、会话信息等。
  • 扩展问题: 请详细说明sessionStorage和localStorage的区别。
  • 扩展问题: 请描述如何使用Web Storage API存储对象或数组。
  • 扩展问题: 请举例说明在什么情况下使用Web Storage API比使用Cookies更合适。

问题2: 请描述HTML5的Web Worker API及其作用。

  • 考点: HTML5多线程技术。
  • 答案: HTML5的Web Worker API允许在后台线程中运行JavaScript代码,从而不会影响页面的性能。这适用于需要处理大量计算或I/O操作的任务,如图像处理、数据处理等。这有助于提高网页的性能,尤其是在处理大数据量或复杂计算时。
  • 扩展问题: 请解释为什么在Web Worker中使用全局变量会导致问题。
  • 扩展问题: 请描述如何在Web Worker中与主线程进行通信。
  • 扩展问题: 请举例说明Web Worker API在处理大数据量时的优势。

问题3: 请解释HTML5的Web Sockets API及其与传统的AJAX通信的差异。

  • 考点: HTML5网络通信技术。
  • 答案: Web Sockets提供了一种全双工的通信机制,允许服务器和客户端之间进行实时通信。与传统的AJAX通信相比,Web Sockets具有更快的通信速度和更好的性能。它常用于需要实时数据交换的应用,如聊天应用、游戏等。
  • 扩展问题: 请描述Web Sockets的持久连接是如何实现的。
  • 扩展问题: 请解释Web Sockets API在处理长连接时的优势。
  • 扩展问题: 请举例说明在什么情况下使用Web Sockets API比使用传统的AJAX更合适。

问题4: 请描述HTML5的Canvas API及其在网页中的使用场景。

  • 考点: HTML5图形和动画技术。
  • 答案: Canvas API允许在网页中使用JavaScript绘制图形、动画和其他视觉效果。它广泛用于游戏开发、数据可视化、图形设计等领域。例如,在创建一个动态图表时,可以使用Canvas API绘制图表元素并实现动画效果。
  • 扩展问题: 请描述如何使用Canvas API绘制一个简单的图形。
  • 扩展问题: 请解释如何在Canvas API中使用路径和形状。
  • 扩展问题: 请举例说明Canvas API在创建游戏时的好处。

问题5: 请描述HTML5的Web Audio API及其在网页中的使用场景。

  • 考点: HTML5音频处理技术。
  • 答案: Web Audio API提供了强大的音频处理功能,包括音频合成、音频效果、音频混合等。它常用于音乐制作、音效设计、实时音频处理等场景。例如,在创建一个音乐播放器时,可以使用Web Audio API处理音频文件并实现音效效果。
  • 扩展问题: 请解释如何在Web Audio API中处理音频文件。
  • 扩展问题: 请描述如何使用Web Audio API创建音频合成效果。
  • 扩展问题: 请举例说明Web Audio API在音乐制作时的优势。

问题6: 请描述HTML5的WebRTC API及其在网页中的应用。

  • 考点: HTML5实时通信技术。
  • 答案: WebRTC API提供了一种在网页中实现实时通信的方法,包括视频会议、语音聊天、屏幕共享等。它不需要安装额外的插件,直接在浏览器中运行。这常用于视频会议、远程协作等场景。
  • 扩展问题: 请解释WebRTC如何处理网络抖动和延迟。
  • 扩展问题: 请描述如何在WebRTC中实现视频会议功能。
  • 扩展问题: 请举例说明WebRTC API在实时通信应用中的优势。

问题7: 请描述HTML5的地理定位API及其使用场景。

  • 考点: HTML5位置感知技术。
  • 答案: 地理定位API允许网页获取用户的地理位置信息。这常用于地图服务、导航应用、基于位置的服务(LBS)等场景。例如,在创建一个导航应用时,可以使用地理定位API获取用户的当前位置并显示导航路线。
  • 扩展问题: 请解释如何处理地理定位API中的错误。
  • 扩展问题: 请描述如何在地理定位API中使用高精度定位。
  • 扩展问题: 请举例说明地理定位API在LBS应用中的优势。

问题8: 请描述HTML5的CSS3过渡和动画属性及其在网页中的使用场景。

  • 考点: HTML5与CSS3的结合。
  • 答案: CSS3过渡和动画属性允许网页中的元素平滑地过渡到新的状态或执行动画效果。它们常用于按钮点击效果、导航栏切换、页面加载动画等场景。例如,在创建一个动画导航栏时,可以使用CSS3过渡和动画属性为导航栏添加平滑的动画效果。
  • 扩展问题: 请解释CSS3过渡和动画属性的异同。
  • 扩展问题: 请描述如何使用CSS3过渡和动画属性创建复杂的动画效果。
  • 扩展问题: 请举例说明CSS3过渡和动画属性在网页设计中的优势。

问题9: 请描述HTML5的WebGL API及其在网页中的应用。

  • 考点: HTML5高级图形技术。
  • 答案: WebGL API允许在网页中使用JavaScript直接操作底层图形硬件,以实现高性能的3D图形和动画效果。它常用于游戏开发、虚拟现实(VR)、增强现实(AR)等场景。例如,在创建一个3D游戏时,可以使用WebGL API实现3D场景和角色动画。 这些高级HTML面试题涉及HTML5的高级特性和API,要求面试者对HTML5有更深入的理解和应用能力。
  • 扩展问题: 请解释如何在WebGL API中使用着色器。
  • 扩展问题: 请描述如何在WebGL API中处理3D模型。
  • 扩展问题: 请举例说明WebGL API在创建3D游戏时的优势。