Web Worker
概述:
JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力。注:js作为单线程不适合处理多计算任务;
作用:
为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。
Web Worker使用注意点:
(1)同源限制
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
(2)DOM 限制
Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document
、window
、parent
这些对象。但是,Worker 线程可以navigator
对象和location
对象。
(3)通信联系
Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。
(4)脚本限制
Worker 线程不能执行alert()
方法和confirm()
方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。
(5)文件限制
Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://
),它所加载的脚本,必须来自网络。
基本用法
1. 创建主线程
let worker = new Worker("./worker.js") //对应一个js文件
Worker()
构造函数的参数是一个脚本文件,该文件就是 Worker 线程所要执行的任务。由于 Worker 不能读取本地文件,所以这个脚本必须来自网络。如果下载没有成功(比如404错误),Worker 就会默默地失败。
2. 主线程向Worker线程发布数据
主线程通过调用
worker.postMessage()
方法,向 Worker线程发布数据。
worker.postMessage('Hello Worker');
3. 主线程通过worker.onmessage
指定监听函数,接收子线程发回来的数据
worker.addEventListener("message",function(ev){
console.log(ev.data) //子线程发回来的数据在ev对象的data里
},false)
worker.addEventListener("error",function(e){ //监听子线程的错误
console.log([
'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
].join(''));)
},false)
通过事件对象的
data
属性可以获取 Worker 发来的数据。
4. 关闭Worker线程
使用完毕,为了节省系统资源,必须关闭 Worker。
worker.terminate();
对应的Worker线程
1. Worker 线程通过监听message
事件,来获取主线程发布的数据.
self.addEventListenner("message",function(ev){
console.log(ev.data);
},false);
//两种都可以
//this.addEventListenner("message",function(ev){
// self.postMessage(ev.data);
//});
self
this
都代表子线程自身,即子线程的全局对象。
2. 向主线程发布消息
Worker线程通过
self.postMessage()
方法用来向主线程发送数据。
self.postMessage(ev.data);
3. 关闭自身线程
Worker 线程 可以通过 close方法关闭Worker线程(也就是自身)
使用完毕,为了节省系统资源,必须关闭 自身。
self.close();
例子:
// index.html
document.onclick = function(){
console.time(1) //开始计算之间代码使用的时间
// 创建work线程
let worker = new Worker('worker.js');//子线程1
let workers =new Worker("workers.js");//子线程2
// 向work发布数据
worker.postMessage(5000);
// 主线程通过onmessage事件获取数据
worker.addEventListener("message",function(ev){
console.log(ev)
box.innerHTML = ev.data
worker.terminate();//关闭Worker线程
},false)
console.timeEnd(1)//结束计算
}
//worker.js
this.addEventListener("message", function(ev){
console.log(ev.data)
let str = ''
for(let i = 1; i < ev.data; i++){
str += String.fromCharCode(i)
}
// 将结果发回主线程
self.postMessage(str)
},false)
Worker构造函数
浏览器原生提供
Worker()
构造函数,用来供主线程生成 Worker 线程。
Worker()
构造函数,可以接受两个参数。第一个参数是脚本的网址(必须遵守同源政策),该参数是必需的,且只能加载 JS 脚本,否则会报错。第二个参数是配置对象,该对象可选。它的一个作用就是指定 Worker 的名称,用来区分多个 Worker 线程。
let worker = new Worker(jsUrl,options)
// 主线程
let Worker = new Worker('worker.js', { name : 'myWorker' });
// Worker 线程
self.name // myWorker