HTML5简单入门系列(四)
前言
今天这篇内容主要讲述HTML 5 Web Worker(一种支持前端js多线程的技术)。
工作线程(Web Worker)
web worker介绍
W3C 在 HTML5 的规范中提出了工作线程(Web Worker)的概念,工作线程允许开发人员编写能够长时间运行而不被用户所中断的后台程序, 去执行事务或者逻辑,并同时保证页面对用户的及时响应。
工作线程的出现使得在 Web 页面中进行多线程编程成为可能。众所周知,传统页面中(HTML5 之前)的 JavaScript 的运行都是以单线程的方式工作的,虽然有多种方式实现了对多线程的模拟(例如:JavaScript 中的 setinterval 方法,setTimeout 方法等),但是在本质上程序的运行仍然是由 JavaScript 引擎以单线程调度的方式进行的。在 HTML5 中引入的工作线程使得浏览器端的 JavaScript 引擎可以并发地执行 JavaScript 代码,从而实现了对浏览器端多线程编程的良好支持。
Web Worker的基本原理就是在当前javascript的主线程中,使用Worker类加载一个javascript文件来开辟一个新的线程,起到互不阻塞执行的效果,并且提供主线程和新线程之间数据交换的接口:postMessage,onmessage。
Web Worker使用
Web Worker 可以分为两种不同线程类型,一个是专用线程 Dedicated Worker,一个是共享线程 Shared Worker。两种类型的线程各有不同的用途。下面仅仅对专用工作线程做简要描述。
Web worker的运行原理和两种线程的详细说明请查看这里。
- 创建外部javascript文件。
它是专用线程的执行文件,即复杂的运算都在这里执行,onmessage接收主线程发送来的消息(参数),并将运行结果postMessage回主线程。
- 在创建 web worker 对象之前,请检测用户的浏览器是否支持它。
if(typeof(Worker)!=="undefined")
- 主线程中创建专用线程
在创建专用线程的时候,需要给 Worker 的构造函数提供一个指向 JavaScript 文件资源的 URL,这也是创建专用线程时 Worker 构造函数所需要的唯一参数。当这个构造函数被调用之后,一个工作线程的实例便会被创建出来。下面是创建专用线程代码示例:
var worker = new Worker(jsrefurl);
- 主线程接收专用线程发来的消息
worker.onmessage = function (event) { ... };
- 主线程向专用线程发送消息
worker.postMessage();
- 终止 Web Worker
当我们创建 web worker 对象后,它会继续监听消息(即使在外部脚本完成之后)直到其被终止为止。
如需终止 web worker,并释放浏览器/计算机资源,请使用 terminate() 方法:
worker.terminate();
示例
下面我们使用一个示例说明上述过程。
新建外部web worker 的js文件,命名为webworker.js
onmessage = function (event) { var msg = event.data; for (var i = 0 ; i < msg; i++) { if (!!console && i % 500 == 0) { console.info(i); } } var d = new Date(); postMessage(d); }
新建主线程页面,命名为webworker.html
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> </head> <body> web worker实时时间:<div id="workerTime"></div> <br /> 主线程获取当前时间:<div id="curTime"></div> <button onclick="mainthread()">主线程获取时间</button> <script> var interval; if (typeof Worker != undefined) { var worker = new Worker("webworker1.js"); worker.onmessage = function (event) { document.getElementById("workerTime").textContent = event.data; } interval = setInterval('worker.postMessage("1000000")', 1000); } function mainthread() { document.getElementById("curTime").textContent = new Date(); } function stop() { clearInterval(interval);
worker.terminate(); } setTimeout(stop, 60000);//60秒之后清理interval </script> </body> </html>
代码很简单,只是为了说明webworker线程不会阻塞主线程(即实现前端多线程)。
示例中我们将webworker线程设置interval不断发起请求,使用一个循环在模仿复杂操作,或者你也可以在js中加入其他操作来模拟耗时操作。
定义了一个按钮,在主线程中获取当前时间。我们可以随时点击该按钮调用主线程的方法,而其不会受到web worker线程的影响。
运行效果我就不贴图了,各园友粘贴代码即可运行查看效果。
Web Workers 和 DOM
由于 web worker 位于外部文件中,它们无法访问下列 JavaScript 对象:
- window 对象
- document 对象
- parent 对象
小结
本文示例很简单,但是麻雀虽小五脏俱全。
主线程新建web worker,发送消息及接收消息,web worker 接收及反馈消息,主线程主动停止web worker线程等全都使用到了。
相信看完这个简介和示例,对web worker也有了一定掌握。
参考
深入 HTML5 Web Worker 应用实践:多线程编程