抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

概念

解决JS单线程,遇到计算密集型或高延迟的任务时发生阻塞的问题
Web Worker 的作用,就是允许主线程创建 Worker 线程,承担一些费时的任务
Worker线程可以有多个,但是使用完最好计时关闭

一个简单的例子帮助理解

改进前:

1
2
3
4
5
6
7
8
9
10
11
12
<body>
<button id="btn">点击</button>
<h1 id="num"></h1>
<script>
//在子线程 模拟一个耗时操作
for (var i = 0; i < 1000000000; i++) { }
num.innerHTML = i;
box.onclick = function () {
alert("耗时操作导致页面阻塞,打开慢");
}
</script>
</body>

主线程中存在耗时任务,发生阻塞
改进后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<body>
<button id="btn">点击</button>
<button id="stop">停止子线程</button>
<h1 id="num"></h1>
<script>
// 创建子线程。把耗时操作放在子线程的文件中,Worker不能读取本地文件,脚本【必须来自网络,并且同源】
var webWorker = new Worker('./worker.js')
webWorker.onmessage = function (e) {
num.innerHTML = e.data
}
btn.onclick = function () {
alert("有子线程后主线程快得多了");
}
stop.onclick = function () {
// 【终止Web Worker】
webworker.terminate();
}
</script>
</body>

子线程

1
2
3
4
5
6
(function  () {
//模拟一个耗时操作
for (var i = 0; i < 1000000000; i++) { }
//耗时操作完毕后,调用postMessage方法回到主线程,并且把数据传回去
postMessage(i);
})();

在主线程创建web worker子线程,让子线程承担费时任务,主线程不会阻塞

Web Worker的限制

  • new 传递的脚本文件必须来源网络并同源
  • 无法访问DOM节点;
  • 无法调用alert()或者confirm之类的函数;
  • 无法访问window、document之类的浏览器全局变量;但是可以用navigator对象和location对象

不过Web Worker中的Javascript依然可以使用setTimeout(),setInterval()之类的函数,也可以使用XMLHttpRequest对象来做Ajax通信

使用方法

主线程

1
2
3
4
var worker = new Worker('work.js') // 用new创建子线程,参数是一个同源网络的脚本文件
worker.postMessage('Hello World'); // 主线程向 Worker 发消息
worker.onmessage = function(ev) { console.log(ev.data) } // 主线程通过监听message事件,接收子线程发回来的消息(事件的data属性)
worker.terminate() // 关闭 Worker

worker线程

1
2
3
addEventListener('message', function (evt) { console.log(ev.data) } // 同理通过监听message事件,接收主线程发回来的消息(事件的data属性)
self.postMessage('Hello World') /// 向主线程发送消息
self.close() // 关闭 Worker

使用XMLHttpRequest与服务端通信

在子线程文件中写:

1
2
3
4
5
6
7
8
addEventListener("message", function(evt){  
var xhr = new XMLHttpRequest();
xhr.open("GET", "某个服务器的url");
xhr.onload = function(){
postMessage(xhr.responseText);
};
xhr.send();
},false);

上面的代码向服务器发出GET请求,并注册了获取数据后的onload事件。结果是获得数据后把数据传给主线程

通过Error事件捕捉错误信息

Web Worker恰恰提供了error事件,供开发者捕捉错误信息

1
2
3
4
5
6
var worker = new Worker("scripts/lengthytask.js");  
worker.addEventListener("error", function(evt){
alert("Line #" + evt.lineno + " - " + evt.message + " in " + evt.filename);
}, false);
worker.postMessage(10000);
});

如上可见, Worker对象可以绑定error事件;而且evt对象中包含错误所在的代码文件(evt.filename)、错误所在的代码行数(evt.lineno)、以及错误信息

参考资料
阮一峰-Web Worker 使用教程
关于Web Worker你必须知道的7件事

评论