天天看点

js多线程Web Worker

我们知道JavaScript是单线程模型,即所有任务都在一个线程上完成,前面一个任务如果没有执行完成,后面的任务就只能等待。如果在遇到耗时的计算时,程序就会阻塞在这里,这对用户来说时不可接受的。因此我们在遇到耗时或者大量计算的时候就可以使用web worker。

什么是web worker?web worker可以为JavaScript创建多线程,且web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。主线程在运行的时候,worker也在后台运行,两者互不干扰,当worker线程完成任务后就可以将结果返回给主线。

使用Web Worker 有以下几个使用注意点:

1. 同源限制

worker子线程必须与主线程是同源

2. DOM限制

Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。

3. 主线程与子线程间的通信

Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过postMessage消息完成。

4. 脚本限制

Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。

5. 文件限制

Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。

基本使用–专用线程

专用线程会随当前页面的关闭而结束,所以专用线程只能被创建它的页面访问

  1. 主线程
// 判断浏览器是否支持worker线程
if(window.Worker) {
    // 主线程通过new 来开启子线程,Worker构造函数的参数是一个脚本文件,由于Worker不能读取本地文件,因此该文件必须是来源于网络
    // 本地通过搭建临时服务来读取脚本文件,但是在线上环境需要填写网络路径,且必须是同源
    var worker = new Worker('./worker.js');
    worker.postMessage('hello worker!');
} else {
    console.log('浏览器不支持worker子线程。。。');
}
worker.addEventListener('message', function(res) {
    console.log('收到子线程的消息:' + JSON.stringify(res.data));
    // 关闭worker线程
    worker.terminate();
})
                
  1. 子线程
// 通过监听message来接受主线程中的消息
addEventListener('message', function(res) {
    // 子线程向主线程中发生消息
    this.postMessage('已收到主线程的消息。。。');
})
                

开启临时服务结果:

js多线程Web Worker

没有开启临时服务时,会报错

js多线程Web Worker

基本使用–共享线程

共享线程可以被多个页面访问,因此只有当所有关联的的页面都关闭的时候,共享线程才会结束,共享线程必须带上port

1> 主线程页面index.html

向共享子线程中发送数据

// 判断浏览器是否支持worker线程
if(window.SharedWorker) {
    // 主线程通过new 来开启共享子线程,SharedWorker构造函数的参数是一个脚本文件,由于SharedWorker不能读取本地文件,因此该文件必须是来源于网络
    var worker = new SharedWorker('./worker.js');
    // 向子线程中发送数据
    var obj = {
        txt:'hello SharedWorker!', 
        type: 'send'
    }
    worker.port.postMessage(obj);
} else {
    console.log('浏览器不支持SharedWorker子线程。。。');
}

worker.port.onmessage = function(res) {
    console.log('收到子线程的消息:' + JSON.stringify(res.data));
}
                

2> 共享子线程worker.js

共享子线程必须使用 onconnect 来连接到主线程的端口,然后可以在onconnect event的ports属性中获取到与该worker相关联的端口并向主线程发送数据

下面共享接受第一个主线程发送的数据并存储,当第二个页面主线程发送获取数据时,返回第一个主线程发送的数据。

// 定义一个变量来接受主线程的数据
var msg = ''; 
onconnect = function(e) {
    var port = e.ports[0];
    port.onmessage = function(res) {
        if(res.data.type == 'send') {
            // 存储主线程发来的数据
            msg = res.data.txt;
            // 子线程向主线程中发生消息
            port.postMessage('已收到主线程的消息。。。');
        } else if (res.data.type == 'get') {
            // 其他页面获取共享线程中的数据
            port.postMessage(msg);
        }
    }
}
                

3> 主线程index2.html

向子线程中发送数据,获取上一个线程存储的数据

// 判断浏览器是否支持worker线程
if(window.SharedWorker) {
     // 主线程通过new 来开启共享子线程,SharedWorker构造函数的参数是一个脚本文件,由于SharedWorker不能读取本地文件,因此该文件必须是来源于网络
     var worker = new SharedWorker('./worker.js');
     // 向子线程中获取上一个线程存储的数据
     worker.port.postMessage({txt:'', type: 'get'});
 } else {
     console.log('浏览器不支持SharedWorker子线程。。。');
 }

 worker.port.onmessage = function(res) {
     console.log('收到子线程的消息:' + JSON.stringify(res.data));
 }
                

运行第一个页面的时候返回的结果如下:

js多线程Web Worker

运行第二个页面的时候就会返回第一个页面发送的数据 hello SharedWorker!

js多线程Web Worker