# Web Worker
# 介绍
Web worker 是工作线程的意思,是HTML5中新提出的概念,目前的支持情况如下:Worker support on caniuse (opens new window)
Web Worker的目的,就是为JavaScript创造多线程环境,允许主线程将一些任务分配给子线程。在主线程运行的同时,子线程在后台运行,两者互不干扰。等到子线程完成计算任务,再把结果返回给主线程。因此,每一个子线程就好像一个“工人”(worker),默默地完成自己的工作。这样做的好处是,一些高计算量或高延迟的工作,被worker线程负担了,所以主进程(通常是UI进程)就会很流畅,不会被阻塞或拖慢。
# Worker
Worker之间 以及他们与主程序之间,不会共享任何作用域或者资源,那样子会把多线程编程里面带来的所有问题都带到前端领域
在Worker内部是无法访问主程序的任何资源的。这意味着你不能访问它的DOM环境,也不能访问页面的DOM或者其他资源。这是一个完全独立的线程。
Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。
你可以做的
- 网络操作(Ajax)
- 设定定时器
- 访问几个常见的全局变量 navigator location JSON
- 通过importScripts向Worker加载额外的JavaScript脚本 (同步加载)
# 功能
# Web Worker通过消息机制和主线程通讯
eg:
//index.js
(function () {
var myWorker = new Worker("my_task.js");
myWorker.onmessage = function (oEvent) {
console.log("Hi, you are " + oEvent.data.name);
};
//Send message to sub therad
myWorker.postMessage({ name: 'Tom' });
})()
这是主线程中的一部分脚本,my_task.js为子线程要执行的脚本,主线程通过监听子线程的message事件被动获取子线程的通知,通过执行postMessage主动向子线程发送消息。同样子线程内也是通过类似方式跟主线程互发消息。
//my_task.js
//可以直接调用,也可以在onmessage函数中调用
postMessage("I am working now");
onmessage = function (oEvent) {
console.log('Hi, you are ' + oEvent.data.name)
postMessage({ name: 'Sam' });
};
子线程最基本要实现的方法就是onmessage,这个用于获取主线程的通知。postMessage用于向主线程主动发送通知。
# 值传递
对于Web Worker的参数传递,简单总结就是:Web Worker与主线程之间的参数传递是使用深拷贝的方式。无论被传递的是字符串还是JSON,都是使用深拷贝的方式
# 子线程创建子线程
工作线程也可以创建自己的子线程,并且使用同样的消息机制在父子线程之间交换数据
# 使用的地方
- 处理密集型数字计算
- 大数据排序
- 数据处理(压缩,音频分析,图像处理)
- 高流量的网络通信
# 使用的限制
- 同源限制
- DOM限制
- 通信限制
- 脚本限制
- 文件限制
同源限制 子线程加载的脚本文件,必须与主线程的脚本文件在同一个域
DOM限制 Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象
通信限制 Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。
脚本限制 Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。
文件限制 Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。
# 如何使用
# 新建和启动线程
主线程采用new命令,调用Worker构造函数,可以新建一个子线程
var worker = new Worker('work.js');
Worker构造函数的参数是一个脚本文件,这个文件就是子线程所要完成的任务,上面代码中是work.js
子线程新建之后,并没有启动,必需等待主线程调用postMessage方法,即发出信号之后才会启动。postMessage方法的参数,就是主线程传给子线程的信号。它可以是一个字符串,也可以是一个对象。
worker.postMessage("Hello World");
worker.postMessage({method: 'echo', args: ['Work']});
# 子线程的事件监听
子线程必须有一个回调函数去监听message事件 两种方式:
//1. addEventListener
self.addEventListener('message', function(e) {
self.postMessage('You said: ' + e.data);
}, false);
self代表子线程自己
//2.onmessage
self.onmessage = function(event) {
var method = event.data.method;
var args = event.data.args;
var reply = doSomething(args);
self.postMessage({method: method, reply: reply});
};
# 主线程的事件监听
对于主线程和上述的子线程添加事件监听是完全一样的
# 错误处理
主线程可以监听子线程是否发生错误。如果发生错误,会触发主线程的error事件
worker.onerror(function(event) {
console.log(event);
});
// or
worker.addEventListener('error', function(event) {
console.log(event);
});
# 关闭子线程(释放资源)
如果不是需要持续执行任务的工作线程,最好在其任务完成后关闭掉。 有两个方法可以完成这个工作:
webworker.terminate()
这个是在主线程用于关闭子线程的;self.close()
这个是子线程关闭自身的方法。
var worker = new Worker('http://url.com/xxx');
worker.addEventListener('message', function(event){
//处理数据
event.data
worker.terminate(); //在worker的外部关闭worker
})
worker.postMessage('e le me?');
//worker.js
let self = addEventListener('message', function(){
self = postMessage('i am full');
self.close(); //在worker的内部关闭worker
})
# 参考
- Web Worker 使用教程 (opens new window)
- http://blog.csdn.net/zwjabcd/article/details/50339135
- http://javascript.ruanyifeng.com/htmlapi/webworker.html#toc0
← Services Worker font →