问题:
长时间运行的JavaScript进程会导致浏览器冻结用户界面,让用户感觉屏幕“冻结”了。
解决:
使用Web Workers,浏览器实现Web Workers 规范的方式有很多种,可以使用线程、后台进程或者运行在其他处理器核心上的进程等。这些具体实现细节并没有那么重要,重要的是开发人员可以放心的运行JavaScript了。
1、使用Worker
var worker = new Worker("worker.js");//worker.js是要执行的js代码
上述代码会导致浏览器下载worker.js文件,但是不会执行它,只有worker接收到消息才会实际执行worker.js文件中的代码.
页面和worker.js之间传递消息是使用postMessage()。
- postMessage()
postMessage()的参数可以是任何能够被序列化的值。
worker和页面通信是依靠message和error事件
- 通过为message和error事件指定事件处理函数,来处理从页面中传递过来的数据。数据都是保存在event.data中
- 当worker不能完成给定的任务时,会触发error事件。Worker内部的JavaScript在执行过程中只要遇到错误,就会触发error事件。发生error事件时,event对象中包含三个属性:filename发生错误的文件名,lineno代码行号,message完整的错误信息。
建议在使用Worker时,都要指定onerror事件处理程序。
worker.onerror = function (event) {console.log(……);}
terminate( ),任何时候,只要调用terminate()就可以停止Worker的工作。Worker中的代码会立即停止执行,后续的所有过程都不会发生(包括error和message事件)
2、Web Worker 全局作用域
- Web Worker 所执行的JavaScript代码完全在另一个作用域中,与当前网页中的代码不共享作用域。 在Web Worder中,也有一个全局对象,其中的代码不可以访问页面中的DOM,也无法通过任何方式改变/影响页面的外观。
- Web Worker中的全局对象就是其本身,即在这个特殊的作用域中,this=self=worker对象
当页面在worker对象上调用postMessage()时,数据会以异步方式被传递给worker,进而触发worker对象中的message对象。为了处理来自页面中的数据,worker中创建onmessage事件处理程序来处理数据。
- importScripts( )。刚才说到worker不能访问DOM,所以其不能动态创建script标签,但这并不意味着worker不能添加其他脚本。importScripts()可以实现。这个方法接收一个或多个JavaScript文件的URL,每个加载的过程都是异步的,因此所有脚本加载并执行之后,importScripts()才会执行。
3、一个实例
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>WebWorker实现多线程</title>
</head>
<body>
<script type="text/javascript">
(function(){
var worker = new Worker("worker.js");//创建worker对象
var data = 100;
worker.onmessage = function (event) {
alert("Hello:" + event.data);
};
worker.postMessage(data);
})();
</script>
</body>
</html>
worker.js
self.onmessage = function (event) {
var data = event.data;
data = data + 1;
self.postMessage(data);
}
在index.html中有一个变量data,初始值是100.我们在worker.js中,对data进行加1操作。让index页面alert出处理后的data值。
首先,在index中创建了worker对象,其指向worker.js这个文件。
在index.html中指定了worker的onmessage事件处理程序,通过event.data来接收worker.js传来的数据。调用postMessage()来传递index.html中的data。
在worker.js中,指定onmessage事件处理程序来处理index.html中传递来的数据,对其进行+1操作,再把数据通过postMessage()传递过去。