写作不易,Star是最大鼓励,感觉写的不错的可以给个Star⭐,请多多指教。本博客的Github地址

javaScript语言采用的是单线程模型,也就是说,所有任务排成一个队列,一次只能做一件事。 Web Worker的目的: 就是为JavaScript创造多线程环境,允许主线程将一些任务分配给子线程。在主线程运行的同时,子线程在后台运行,两者互不干扰。等到子线程完成计算任务,再把结果返回给主线程。 当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成。web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行。可以让web应用程序具备后台处理能力,对多线程的支持非常好。

Web Worker API

  • new Worker('后台处理的JS地址')

使用Web Worker: 实例化Worker对象并传入要执行的Javascript文件名就可以创建一个新的Web Worker。 例如:var worker = new Worker('worker.js');

这行代码会导致浏览器下载worker.js,但只有Worker接收到消息才会实际执行文件中的代码。

  • 利用postMessage传输数据 要给Worker传递消息,可以使用postMessage()方法。 Worker是通过message和error事件与页面通信的。来自Worker的数据保存在event.data中。Worker返回的数据也可以是任何能够被序列化的值。 Worker不能完成给定的任务时就会触发error事件。具体来说,Worker内部的JavaScript在执行过程中只要遇到错误,就会触发error事件。发生error事件时,**事件对象中包含3个属性:**filename、lineto和message,分别表示发生错误的文件名、代码行号和完整的错误信息
  • **terminate() 方法:**终止 web worker,并释放浏览器/计算机资源(这个方法是在页面中调用的)
  • importScripts('导入其他JS文件')

Worker全局作用域

关于Web Worker,**最重要的是:**要知道它所执行的JavaScript代码完全在另一个作用域中,与当前网页中的代码不共享作用域。在Web Worker中,同样有一个全局对象和其他对象以及方法。但是,Web Worker中的代码不能访问DOM,也无法通过任何方式影响页面的外观。 Web Worker中的全局对象是worker对象本身。也就是说,在这个特殊的全局作用域中,this和self引用的都是worker对象。 为了便于处理数据,Web Worker本身也是一个最小化的运行环境:

  • 最小化的navgator对象 : online、appName、appVersion、userAgent、platform
  • 只读的location对象 : 所有属性都是只读的
  • self : 指向全局 worker 对象
  • 所有的ECMA对象,Object、Array、Date等
  • XMLHttpRequest构造器
  • setTimeout和setInterval方法
  • close()方法,立刻停止worker运行(在worker内部使用,而terminate() 方法是在页面中调用的)
  • importScripts方法

在Worker的全局作用域中,我们可以调用importScripts方法来接收一个或者多个JavaScript文件的URL。每个加载过程都是异步进行的,因此所有脚本加载并执行之后,importScripts()才会执行。 例如:

importScripts('file1.js','file2.js');
1

即使file2.js先于file1.js下载完,执行的时候仍然会按照先后顺序执行。这些脚本都是在Worker的全局作用域中执行的。Worker中的脚本一般都具有特殊的用途,不会像页面中的脚本那么功能宽泛。

Web Worker的运行环境与页面环境相比,功能是相当有限的。 Demo1:

<body>
<p>计数:<span id="res"></span></p>
<input type="button" name="" value="开始计数" onclick="startWorker()">
<input type="button" name="" value="停止计数" onclick="stopWorker()">
<script type="text/javascript">
var w;
function startWorker(){
	//先判断是否支持Web Worker
	if(typeof(Worker) !== "undefined"){
		if(typeof(w) == "undefined"){
		//新建一个worker对象
			w = new Worker("webworker1.js");
		}
		w.onmessage = function(e){
			document.getElementById("res").innerHTML = e.data;
		}
	}else{
		alert("对不起,当前浏览器不支持web Workers");
	}
}
function stopWorker(){
	w.terminate();
	w = undefined;
}
</script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

webworker1.js

var i=0;
function numCount(){
	i++;
	self.postMessage(i);
	setTimeout("numCount()",500);
}
numCount();
1
2
3
4
5
6
7

Demo2:

<script type="text/javascript">
var data = [23,87,45,12,56,9,34];
console.log("排序前:"+data);
var worker = new Worker("webworkers2.js");
worker.onmessage = function(e){
	var data = e.data;
	console.log("排序后:"+data);//排序后:9,12,23,34,45,56,87
};
worker.onerror = function(e){
	console.log("Error:"+e.filename+"("+e.lineto+"):"+e.message);
}
worker.postMessage(data);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13

webworker2.js

//这里self引用的是Worker全局作用域中的worker对象(与页面中的Worker对象不是同一个对象)
self.onmessage = function(e) {
	var data = e.data;
	data.sort(function(a, b) {
		return a-b;//从小到大排序
	});
	//Worker完成工作后,通过调用postMessage()可以把数据再发回页面
	//这里将数组排序后的结果发回页面
	//排序的确是比较消耗时间的操作,因此转交给Worker做就不会阻塞用户界面了
	self.postMessage(data);
};
1
2
3
4
5
6
7
8
9
10
11

当页面在worker对象上调用postMessage()方法时,数据会以异步方式被传递给worker,进而触发worker中的message事件。为了处理来自页面的数据,同样也需要创建一个onmessage事件处理程序。 **Web Worker:**可以运行异步Javascript代码,避免阻塞用户界面。在执行复杂计算和数据处理的时候,这个API非 常有用;否则,这些任务轻则会占用很长时间,重则会导致用户无法与页面交互。

参考文档

  1. Web Worker 使用教程