部分增强Web技术(3)

三、Web Worker

1.概述

JavaScript语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力。

Web Worker的作用,就是为JavaScript创造多线程环境,允许主线程创建Worker线程,将一些任务分配给后者运行。在主线程运行的同时,Worker线程在后台运行,两者互不干扰。等到Worker线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被Worker线程负担了,主线程(通常负责UI交互)就会很流畅,不会被阻塞或拖慢。

Worker线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了Worker比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。

 

2.注意

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

1)同源限制分配给Worker线程运行的脚本文件,必须与主线程的脚本文件同源(同协议、同域名、同端口)。

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

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

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

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

 

3.基本用法

(1)主线程

主线程采用new命令,调用Worker()构造函数,新建一个Worker线程。

var worker = new Worker('...work.js');

Worker()构造函数的参数是一个脚本文件,该文件就是Worker线程所要执行的任务。由于Worker不能读取本地文件,所以这个脚本必须来自网络。如果下载没有成功(比如404错误),Worker线程的任务就会无法执行。

 

然后,主线程调用worker.postMessage()方法,向Worker发消息。这个方法的参数就是主线程传给Worker的数据,可以是各种数据类型,包括二进制数据,如:

worker.postMessage('Hello World');

worker.postMessage({method: 'echo', args: ['Work']});

 

接着,主线程通过worker.onmessage指定监听函数,接收子线程发回来的消息事件对象的data属性可以获取Worker发来的数据

  worker.onmessage = function(event){

console.log('Received message ' + event.data);

}

 

Worker完成任务以后,主线程就可以通过worker.terminate();把它关掉,节约资源。

 

2Worker线程

Worker线程内部需要有一个监听函数,监听message事件

self.addEventListener('message', function(event){

self.postMessage('You said: ' + event.data);

}, false);

 

除了使用self.addEventListener()指定监听函数,可以使用self.onmessage指定。监听函数的参数是一个事件对象,它的data属性包含主线程发来的数据。self.postMessage()方法用来向主线程发送消息。

 

Worker同样可以加载其它脚本完成任务(相当于子线程里的子线程),Worker内部如果要加载其他脚本,有一个专门的方法importScripts(),如:

importScripts('...script1.js');

 

主线程可以监听Worker是否发生错误(Worker内部也可以监听error事件。如果发生错误,Worker会触发主线程的error事件

worker.onerror(function(event){

console.log(['ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message].join(''));

});

// 或者

worker.addEventListener('error', function(event){

// ...

});

 

使用完毕,为了节约资源,需要关闭子线程:

self.close();

 

附实例代码:

<!-- 主线程部分 -->
    <script>
        //由于 Worker 不能读取本地文件,所以这个脚本必须来自网络
        //var worker = new Worker('js/work.js');
        var worker =new Worker('http://39.96.14.133/web1903_6html5API/js/work.js');

        //1.主进程推送给子进程 可以使用对象或者字符串等
        worker.postMessage({method: 'echo', args: ['Work']});
        //worker.postMessage('Hello World');

        //4.接受子进程过来的数据
        worker.onmessage = function (event) {
            console.log('Received message ' + event.data);
        }
        
        //5.使用完毕,为了节省系统资源,必须关闭 Worker
        worker.terminate();
    </script>

<!-- 子线程部分 -->
//2.把数处理后的程序发送给主进程
self.addEventListener('message', function (e) {
    //3.子进程处理传入的参数
    self.postMessage('You said: ' + e.data); //e.data 就是传入的数据
}, false);

//work 进程识别主进程的不同处理
// self.addEventListener('message', function (e) {
//     var data = e.data;
//     switch (data.cmd) {
//       case 'start':
//         self.postMessage('WORKER STARTED: ' + data.msg);
//         break;
//       case 'stop':
//         self.postMessage('WORKER STOPPED: ' + data.msg);
//         self.close(); // Terminates the worker.
//         break;
//       default:
//         self.postMessage('Unknown command: ' + data.msg);
//     };
// }, false);

//5.使用完毕,为了节省系统资源,必须关闭 Worker
self.close();
posted @ 2019-09-20 18:14  我的祈愿  阅读(173)  评论(0编辑  收藏  举报