什么是web worker
定义
Web Workers 使得一个Web应用程序可以在与主执行线程分离的后台线程中运行一个脚本操作。这样做的好处是可以在一个单独的线程中执行费时的处理任务,从而允许主(通常是UI)线程运行而不被阻塞。
它的作用就是给JS创造多线程运行环境,允许主线程创建worker线程,分配任务给后者,主线程运行的同时worker线程也在运行,相互不干扰,在worker线程运行结束后把结果返回给主线程。这样做的好处是主线程可以把计算密集型或高延迟的任务交给worker线程执行,这样主线程就会变得轻松,不会被阻塞或拖慢。这并不意味着JS语言本身支持了多线程能力,而是浏览器作为宿主环境提供了JS一个多线程运行的环境。
不过因为worker一旦新建,就会一直运行,不会被主线程的活动打断,这样有利于随时响应主线程的通性,但是也会造成资源的浪费,所以不应过度使用,用完注意关闭。或者说:如果worker无实例引用,该worker空闲后立即会被关闭;如果worker实列引用不为0,该worker空闲也不会被关闭。
种类
web worker有两类:
一.专用worker
是指标准worker仅在单一脚本且,仅仅能被首次生成它的脚本使用
二.共享worker
可以同时被多个脚本使用。
使用限制
1、同源限制
worker线程执行的脚本文件必须和主线程的脚本文件同源,这是当然的了,总不能允许worker线程到别人电脑上到处读文件吧
2、文件限制
为了安全,worker线程无法读取本地文件,它所加载的脚本必须来自网络,且需要与主线程的脚本同源
3、DOM操作限制
worker线程在与主线程的window不同的另一个全局上下文中运行,其中无法读取主线程所在网页的DOM对象,也不能获取 document、window等对象,但是可以获取navigator、location(只读)、XMLHttpRequest、setTimeout族等浏览器API。
4、通信限制
worker线程与主线程不在同一个上下文,不能直接通信,需要通过postMessage方法来通信。这个过程中数据不是被共享,而是被复制
5、脚本限制
worker线程不能执行alert、confirm,但可以使用 XMLHttpRequest 对象发出ajax请求。
使用
1.生成webWorker
MDN
// 主线程
调用Worker() 的构造器,指定一个脚本的URI来执行worker线程(main.js):
var myWorker = new Worker('worker.js', { name : 'myWorker' });
// Worker 线程
self.name // myWorker
第一个参数是脚本的网址(必须遵守同源政策),该参数是必需的,且只能加载 JS
脚本,否则报错。第二个参数是配置对象,该对象可选。它的一个作用就是指定
Worker 的名称,用来区分多个 Worker 线程。
2.专用worker中消息的接收和发送
通过postMessage() 方法和onmessage事件处理函数触发workers的方法
若:想要向一个worker发送消息时,你只需要这样做(main.js)
first.onchange = function() {
myWorker.postMessage([first.value, 1]);
console.log('Message posted to worker');
}
first代表了元素
当它的值发生改变时,myWorker.postMessage([first.value,value])会将这个值组成数组发送给worker。你可以在消息中发送许多你想发送的东西。
3.在worker中接收到消息后,我们可以写这样一个事件处理函数代码作为响应(worker.js)
onmessage = function(e) {
console.log('Message received from main script');
var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
console.log('Posting message back to main script');
postMessage(workerResult);
}
onmessage处理函数允许我们在任何时刻,一旦接收到消息就可以执行一些代码,代码中消息本身作为事件的data属性进行使用。这里我们简单的对这2个数字作乘法处理并再次使用postMessage()方法,将结果回传给主线程。
4.回到主线程,我们再次使用onmessage以响应worker回传的消息:
myWorker.onmessage = function(e) {
result.textContent = e.data;
console.log('Message received from worker');
}
在这里我们获取消息事件的data,并且将它设置为result的textContent,所以用户可以直接看到运算的结果。
注意: 在主线程中使用时,onmessage和postMessage() 必须挂在worker对象上,而在worker中使用时不用这样做。原因是,在worker内部,worker是有效的全局作用域。
5.终止worker
myWorker.terminate()
worker 线程会被立即杀死,不会有任何机会让它完成自己的操作或清理工作。
close();
而在worker线程中,workers 也可以调用自己的 close 方法进行关闭
6.处理错误
当 worker 出现运行中错误时,它的 onerror 事件处理函数会被调用。它会收到
一个扩展了 ErrorEvent 接口的名为 error的事件。
该事件不会冒泡并且可以被取消;为了防止触发默认动作,worker 可以调用错误
事件的 preventDefault()方法。
错误事件有以下三个用户关心的字段:
message
可读性良好的错误消息。
filename
发生错误的脚本文件名。
lineno
发生错误时所在脚本文件的行号。
具体事例可参考链接,该文章中总结了各种场景中使用的情况