1、简介
我们都知道javaScript
是采用单线程执行的,同一时间只能做一件事,如果采用同步执行的,出现阻塞那么后面的代码将不会执行,HTML5
则提出了Web Worker
标准,表示js
允许多线程,但是子线程完全受主线程控制并且不能操作dom
,只有主线程可以操作dom
,所以js
本质上依然是单线程
语言。
关于js
的运行机制可以参考阮一峰文章JavaScript 运行机制详解:再谈Event Loop
2、web worker
web worker
就是在js
单线程执行的基础上开启一个子线程,进行程序处理,而不影响主线程的执行,当子线程执行完之后再回到主线程上,在这个过程中不影响主线程的执行。
2.1、创建线程
var worker = new Worker('worker.js');
其中的worker.js
是一个单独的js
文件,以上代码创建了一个子线程,还可以使用下面的方式
var worker = new Worker(blob);
传入的参数
- 一个指向
js
文件资源的url
Blob
对象,就是一个包含只读原始数据类文件对象
2.2、线程间通信
web worker
的基本原理是在当前的主线程中加载一个只读文件,来创建一个新的线程,两个线程同时存在且互补阻塞,并且子线程与主线程之间提供了数据交互的接口postMessage
和onmessage
,来进行数据发送和接收。
2.2.1、数据发送
var worker = new Worker('worker.js');
// 第一种传递方式
worker.postMessage(message, transferList);
// 第二种方式
worker.postMessage({
operation:'list_all_users',
// ArrayBuffer Object
input:buffer,
thresold:0.8,
}, [buffer]);
如果要想一个专用线程发送数据,那么我们需要使用线程中的 postMessage 方法。专用线程不仅仅支持传输二进制数据,也支持结构化的 JavaScript 数据格式。在这里有一点需要注意,为了高效地传输 ArrayBuffer 对象数据,需要在 postMessage 方法中的第二个参数中指定它。
2.2.2、数据接收
//方法一
worker.onmessage = function(event){
var data = event.data; //通过event.data来获取传入的参数
}
//方法二
worker.addEventListener("message",target);
2.2.3、示例代码
下面是一段运行在chrome中的参数传递方式:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webWorker</title>
</head>
<body>
<script>
var worker = new Worker("worker.js");
worker.postMessage("123456");
worker.onmessage = function (e) {
console.log(e.data)
};
</script>
</body>
</html>
worker.js
onmessage = function (e) {
console.log(e.data);
postMessage("2222")
};
此时我们的浏览器打印出的log是如下:
2.2.4、异常处理
worker.onerror = function(e){
console.log("error at "+e.filename ":" + e.lineno + e.message)
}
2.2.5、结束线程
worker.terminate();
3、worker 作用域
当我们创建一个新的worker
时,改代码会运行在一个全新的javascript
的环境中(WorkerGlobalScope
)运行,是完全和创建worker
的脚本隔离,这时我们可以吧创建新worker
的脚本叫做主线程,而被创建的新的worker
叫做子线程。
WorkerGlobalScope
是worker
的全局对象,所以它包含所有核心javascript
全局对象拥有的属性如JSON
等,window
的一些属性,也拥有类似于XMLHttpRequest()
等。
但是我们所开启的新的worker
也就是子线程,并不支持操作页面的DOM
。
4、SharedWorker 共享线程
共享线程是为了避免线程的重复使用和销毁过程,降低了系统性能的消耗,共享线程SharedWorker
可以有多个页面的线程链接。
使用SharedWorker
创建共享线程,也需要提供一个javascript
脚本文件的URL
地址或Blob
,该脚本文件中包含了我们在线程中需要执行的代码,如下:
var worker = new SharedWorker('sharedworker.js');
共享线程也使用了message
事件监听线程消息,但使用SharedWorker
对象的port
属性与线程通信如下。
worker.port.onmessage = function(e){
...
}
同时我们也可以使用SharedWorker
对象的port
属性向共享线程发送消息如下。
worker.port.postMessage("message");
摘录
文章大部分类容摘自《指尖上行》一书
参考文献
1、JavaScript 运行机制详解:再谈Event Loop
2、深入 HTML5 Web Worker 应用实践:多线程编程