视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
HTML5新特性之WebWorker
2020-11-27 15:10:15 责编:小采
文档


1、概述

http://www.gxlcms.com/wiki/48.html" target="_blank">JavaScript语言采用的是单线程模型,也就是说,所有任务排成一个队列,一次只能做一件事。随着电脑计算能力的增强,这一点带来很大的不便,无法充分发挥JavaScript的潜能。龙其考虑到,File API允许JavaScript读取本地文件,就更加如此了。

Web Worker的目就,就是为JavaScript创造多线程环境,允许主线程将一些任务分配给子线程。在主线程运行的同时,子线程在后台运行,两者互不干扰。等到子线程完成计算任务,再把结果返回给主线程。因此,每一个子线程就好像一个“工人”(worker),默默地完成自己的工作。

Web Worker有以下几个特点:

  • 同域:子线程加载的脚本文件,必须与主线程的脚本文件在同一个域。

  • DOM:子线程无法读限网页的DOM对象,即document、window、parent这些对象,子线程都无法得到。(但是,navigator对象和location对象可以获得。)

  • 脚本:子线程无法读取网页的全局变量和函数,也不能执行alert和confirm方法,不过可以执行setInterval和setTimeout,以及使用XMLHttpRequest对象发出AJAX请求。

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

  • 使用之前,检查浏览器是否支持这个API。支持的浏览器包括 IE 10+、Firefox 3.6+、Safari 4.0+、Chrome 和 Opera 11,但是手机浏览器还不支持。

    if (window.Worker) { // 支持} else { // 不支持}

    2、新建和启动子线程

    在主线程内部,采用new命令调用Worker方法,可以新建一个子线程。

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

    Worker方法的参数是一个脚本文件,这个文件就是子线程所要完成的任务,上面代码中是work.js。由于子线程不能读取本地文件系统,所以这个脚本文件必须来自网络端。如果下载没有成功,比如出现404错误,这个子线程就会默默地失败。

    子线程新建之后,并没有启动,必需等待主线程调用postMessage方法,即发出信号之后才会启动。

    worker.postMessage('hello world');

    postMessage方法的参数,就是主线程传给子线程的信号。它即可以是一个字符串,也可以是一个对象。

    worker.postMessage({method: 'each', args: ['work']});

    3、子线程的事件监听

    在子线程内,必须有一个回调函数,监听message事件。

    //File: work.jsself.addEventListener('message', function(e) {
    
     self.postMessage('You said: ' + e.data);
    
    }, false);

    self代表子线程自身,self.addEventListener表示对子线程的message事件指定回调函数(直接指定onmessage属性的值也可以)。回调函数的参数是一个事件对象,它的data属性包含主线程发来的信号。self.postMessage则表示,子线程向主线程发送一个信号。

    根据主线程发来的不同的信号值,子线程可以调用不同的方法。

    'message', method = args = reply =);

    4、主线程的事件监听

    主线程也必须指定message事件的回调函数,监听子线程发来的信号。

    // File: main.jsworker.addEventListener('message', function(e) {
     console.log(e.data);
    }, false);

    5、错误处理

    主线程可以监听子线程是否发生错误。如果发生错误,会触发主线程的error事件。

    worker.onerror(function(e) {
     console.log(e);
    });// orworker.addEventListener('error', function(e) {
     console.log(e);
    }, false);

    6、关闭子线程

    使用完毕后,为了节省系统资源,我们必须在主线程调用terminate方法,手动关闭子线程。

    worker.terminate();

    也可以子线程内部关闭自身。

    self.close();

    7、主线程与子线程的数据通信

    主线程与子线程之间的通信内容,可以是文本,也可以是对象。需要注意的是,这种通信是拷贝关系,即是传值而不是传址,子线程对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给子线程,后者再将它还原。

    主线程也子线程这间也可以交换二进制数据,比如File、Blob、ArrayBuffer等对象,也可以在线程之间发送。

    但是,用拷贝方式发送二进制数据,会造成性能问题。比如,主线程向子线程发送一个500MB文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做Transferable Objects。

    如果要使用该方法,postMessage方法的最后一个参数必须是一个数组,用来指定前面发送的哪些值可以被转移给子线程。

    worker.postMessage(arrayBuffer, [arrayBuffer]);

    8、同页面的Web Worker

    通常情况下,子线程载入的是一个单独的JavaScript文件,但是也可以载入与主线程在同一个网页的代码。假设网页代码如下:

    <!DOCTYPE html>
     <body>
     <script id="worker" type="app/worker">
    
     addEventListener('message', function() {
     postMessage('Im reading Tech.pro');
     }, false); </script>
     </body></html>

    我们可以读取页面的script,用worker来处理。

    var blob = new Blob([document.querySelector('#workere').textContent]);

    这里需要把代码当作二进制数据读取,所以使用Blob接口。然后,这个二进制对象转为URL,再通过这个URL创建worker。

    var url = window.URL.createObjectURL(blob);var worker = new Worker(url);

    部署事件监听代码。

    worker.addEventListener('message', function(e) {
     console.log(e.data);
    }, false);

    最后启动worker。

    worker.postMessage('');

    整个页面的代码如下:

    <!DOCTYPE html>
     <body>
     <script id="worker" type="app/worker">
    
     addEventListener('message', function() {
     postMessage('Work done!');
     }, false); </script>
    
     <script>
     (function() { 
     var blob = new Blob([document.querySelector('#worker').textContent]); 
     var url = window.URL.createObjectURL(blob); 
     var worker = new Worker(url);
    
     worker.addEventListener('message', function(e) {
     console.log(e.data);
     }, false);
    
     worker.postMessage('');
     })(); </script>
     </body></html>

    可以看到,主线程和子线程的代码都在同一个网页上面。

    上面所讲的Web Worker都是专属于某个网页的,当该网页关闭,worker就自动结束。除此之外,还有一种共享式的Web Worker,允许多个浏览器窗口共享同一个worker,只有当所有窗口关闭,它才会结束。这种共享式的Worker用SharedWorker对象来创建,因为适用场合不多,这里就省略了。

    下载本文
    显示全文
    专题