1.上面的例子最好放到服务器上运行,线程完成计

作者: 前端  发布:2019-11-22

      因为下个项目中要用到一些倒计时的功能,所以就提前准备了一下,省的到时候出现一下界面不友好和一些其他的事情。正好趁着这个机会也加深一下html5中的多线程worker的用法和理解。

Html5之web workers多线程

Web Workers 是 HTML5 提供的一个javascript多线程解决方案,我们可以将一些大计算量的代码交由web Worker运行而不冻结用户界面。

1、首先看一个实例:

1)js文件(test.js)

 

var fibonacci =function(n) {
    return n <2? n : arguments.callee(n -1) + arguments.callee(n -2);
};
onmessage =function(event) {
    var n = parseInt(event.data, 10);
    postMessage(fibonacci(n));
};

2)html页面(test.html)

 

 

<script type=text/javascript>|r| var worker =new Worker('test.js'); |r| worker.onmessage =function(evt){ |r| alert(evt.data);|r| }|r| function onload() {|r| worker.postMessage(40);|r| }|r| onload();|r| </script>sfsdfdsfdsfdfdsf

 

注意:

 

1.上面的例子最好放到服务器上运行。(chrome不支持本地的)

2.上面的例子可以发现,页面会先渲染body中的html内容,在子线程中去执行负责的计算,等子线程计算完毕后把结果传递给主线程。如果不使用web workers,直接把计算部分放到主线程中,那么浏览器处于单线程中,会顺序执行,导致下面的页面无法加载。

2、web workers流程:

 

WEB主线程:
1.通过 worker = new Worker( url ) 加载一个JS文件来创建一个worker,同时返回一个worker实例。
2.通过worker.postMessage( data ) 方法来向worker发送数据。
3.绑定worker.onmessage方法来接收worker发送过来的数据。
4.可以使用 worker.terminate() 来终止一个worker的执行。

worker新线程:
1.通过postMessage( data ) 方法来向主线程发送数据。
2.绑定onmessage方法来接收主线程发送过来的数据。

3、web workers知识点:
1.worker.onmessage
绑定主线程的message事件,当worker调用postMessage时方法时,绑定的事件处理程序会被调用到,传递来的数据可以使用MouseEvent的data属性获取,通过target属性还可以获取worker对象

2.self是什么
self是woker中对自身的引用,有些像this

3.close()
在worker内部调用close()方法效果和在外部调用worker实例的terminate()方法效果一样,终止worker运行

4.onmessage
在这个句柄内接收外部调用者传递的参数,参数可以通过e.data获取

5.self.postMessage()
没错通过这个方法我们可以在worker内把结果传递给主线程,主线程上绑定的message事件的处理程序会被调。

6.全新的JavaScript环境
当一个Worker实例被创建的时候,它会在一个全新的JavaScript运行环境中,完全和创建worker的脚本分离开,即使我们传递的消息是引用类型它们也是复制传递的,修改worker中的参数不影响创建脚本中的参数。

7.importScripts()
我们可以通过importScripts()方法通过url在worker中加载库函数,如下:
importScripts('utility/dialog.js','common/cookie.js');
方法可以接受多个url,相对地址的url以当前worker为参照,方法会按照参数顺序依次下载运行库函数,如果中间某个脚本出错,剩下的都不会被载入和执行,而且这个方法是同步的,只有所有脚本都加载、运行完后才会返回。
注:importScripts方法可以加载跨域的文件。使用worker的构造函数时的js文件只能是同源的。

8.worker执行模型
worker线程从上到下同步运行它的代码,然后进入异步阶段来对事件及计时器响应,如果worker注册了message事件处理程序,只要其有可能触发,worker就一直在内存中,不会退出,但如果worker没有监听消息,那么当所有任务执行完毕(包括计数器)后,他就会退出。

9.web worker中可以使用什么
1)self自身引用
2)可以使用JavaScript的全局对象:JSON、Date()、Array
3)location对象,但是其属性都是只读的,改了也影响不到调用者
4)navigator对象
5)setTimeout()、setInterval()及其对应清除方法
6)addEventListener()、removeEventListener()
7)最后web worker还支持sub worker和共享worker,这方面没有太仔细看,浏览器兼容性也不讨理想,有兴趣同学可以上网搜索研究一下。

10.web worker 弱点:
1)在worker中不能使用window对象和docuemnt对象(dom对象),即:不能在主、子线程中共享dom操作。
2)不能跨域加载work的js(在使用work的构造方法时)
3)web worker只能用来加载同域下的json数据,而这方面ajax已经可以做到了,而且效率更高更通用。还是让Worker做它自己擅长的事吧。

 

workers多线程 Web Workers 是 HTML5 提供的一个javascript多线程解决方案,我们可以将一些大计算量的代码交由web Worker运行而不冻结用户...

WebWorker类似于浏览器中的多线程操作。之前的JS中,无论你是使用setTimeout、setInterval 还是 使用了XMLHttpRequest,都是在一个线程里面。前两个使用消息队列,XMLHttpRequest则是浏览器会帮你进行闲时进行。归根结底,都是在一个线程里面跑。如果用户想进行一些阻塞操作,很可能会产生卡住页面的情况。甚至于我们想实现一个类似于Android的专用、公用Service,那该怎么办?

本文由云+社区发表

Worker简介

    JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。这些都是我们所公知的。但是随着业务的不断增加,只是单纯的单线程模式已经可能无法满足我们的需求了。于是在html5中新增了后台任务worker API。

w3c中的介绍:web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行。

9159.com ,       worker就是为了JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。开启后台线程,在不影响前台线程的前提下做一些耗时或者异步的操作。因为是不同的线程,所以主线程与worker线程互不干扰。也不会相互打断。所以在一些场景可以提高页面的流程性。Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。

1.Web Worker是什么

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

使用规则

  1. 必须同源:也就是说js文件的路径必须和主线程的脚本同源。防止了外部引用。
  2. dom限制:在worker线程中不能操作dom(document,window,parent)。注意可以使用浏览器的navigator和location对象。
  3. 通讯限制:worker线程和主线程不在一个上下文中所以不能直接通讯。也就是说主线程定义的变量在worker中也是不能使用的。所有只能通过消息完成。
  4. 提示禁止:worker线程不能alert和confirm,这个不知到具体原因?
  5. 传值dom:进行消息通讯也不能传值dom只能是变量。
  6. ie限制:ie9不能使用!ie9不能使用!ie9不能使用!

Web Worker 是HTML5标准的一部分,这一规范定义了一套 API,它允许一段JavaScript程序运行在主线程之外的另外一个线程中。Web Worker 规范中定义了两类工作线程,分别是专用线程Dedicated Worker和共享线程 Shared Worker,其中,Dedicated Worker只能为一个页面所使用,而Shared Worker则可以被多个页面所共享,本文示例为专用线程Dedicated Worker。

9159.com 1img

worker文档

Web Workers API的Worker界面代表了一个可以轻松创建的后台任务,可以将消息发送回其创建者。创建worker就像调用 构造函数并指定要在工作线程中运行的脚本一样简单。

chrome浏览器是多进程架构,分为Browser进程以及Render进程。每打开一个页面,浏览器都会为其分配一个Render进程,webkit以及js都运行在这个进程内。如果要起一个DedicatedWorker,Chrome会在Render进程中起一个线程。如果要起一个SharedWorker就稍微复杂一点,必须起一个专门的进程,并且,相同的SharedWorker不管你创建多少次,都只存在一个。

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

构造函数

worker():创建一个专用的Web worker,在指定的URL上执行脚本。示例:var worker=new Worker('js/setTime.js');

2.使用Dedicated Worker的主页面代码main.js

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

属性

onerror:

这是一个在error事件发生时调用的函数,并且通过该函数冒泡worker。示例:worker.onerror=function(){....};

onmessage:

  这是一个worker中message事件要发生的时候调用的事件。  示例:worker.onmessage=function(){....};

  这个事件一般与postMessage事件同时使用,一个用来发送数据,一个用来接受数据。例如:

 主线程中:

  var jsId = "00001";
  var worker = new Worker('js/setTime.js');
  worker.postMessage(jsId);

 

         worker线程中:

//接受事件参数
onmessage = function(e) {

    console.log(e.data[0])
}

这样就完成了一个主线程向worker线程传递参数的过程。同样如果worker线程要向主线程传递参数反过来写即可。

 onmessageerror:

在消息传递过程出现错误的属性事件。示例:worker.onmessageerror=function(){....};

var worker = new Worker("task.js");
worker.postMessage(
{
  id:1,
  msg:'Hello World'
}
);
worker.onmessage=function(message){
  var data = message.data;
  console.log(JSON.stringify(data));
  worker.terminate();
};
worker.onerror=function(error){
  console.log(error.filename,error.lineno,error.message);
}

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

方法

postMessage:

向线程worker的内部范围发送消息,可以设置参数,发送给worker线程的数据。在onmessage中接受。

terminate:

过多的开启worker线程非常浪费资源所以在使用过后可以终止它,终止方法使用terminate()。示例:worker.terminate();

close:

除了上面的关闭,如果是在worker线程自身也可以使用self.close()关闭。

Dedicated Worker所执行的代码task.js

同源限制

 计时器示例

上面说了那么多都是介绍worker的一些基本属性或者方法的使用。下面通过具体的示例来看效果。

我们就拿最常用的倒计时来做示例说明。很简单的一个例子。我们在业务中经常遇到倒计时业务,在倒计时的时候还要做一些其他的业务。因为js单线程的特性,你会发现你的倒计时在你进行其他业务操作的时候是暂停了的。例如现在是9:57你进行了三秒的业务处理。等业务处理完成应该是:9:54,但是你的倒计时还是9:57.就很明显的说明了这一个现象。

onmessage = function(message){
  var data=message.data;
  data.msg = 'Hi from task.js';
  postMessage(data);
}

分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。

场景业务设计

那么我们现在设计这么一个业务操作,

  • 首先我们页面有一个定时器和一个业务操作按钮(用来模拟耗时的操作)。
  • 然后把定时器写到一个worker中进行倒计时操作。
  • 最后通过消息通讯把每次的倒计时时间发送给主线程让主线程修改显示时间。
  • 结束倒计时完毕结束定时器和线程

 有人可能会说为什么还要回到主线程修改时间显示值,请看一下上面的使用规则,我本来也是打算进行主线程传值dom给worker线程奈何不行只能在回传回来。

在main.js代码中,首先通过调用构造函数,传入了worker脚本文件名,新建了一个worker对象,在我的理解中,这一对象是新创建的工作线程在主线程的引用。随后调用worker.postMessage()方法,与新创建的工作线程通信,这里传入了一个json对象。随后分别定义了worker对象的onmessage事件和onerror事件的回调处理函数,当woker线程返回数据时,onmessage回调函数执行,数据封装在message参数的data属性中,调用 worker 的 terminate()方法可以终止worker线程的运行;当worker线程执行出错时,onerror回调函数执行,error参数中封装了错误对象的文件名、出错行号和具体错误信息。

DOM 限制

代码展示

 Html代码:

<body>
        <div>
            10 :
            00
        </div>

        <button type="button" onclick="business()">耗时操作</button>
 </body>

主线程js代码:

            //页面加载完成后初始化
            window.onload = function() {
                //创建定时器线程
                var worker = new Worker('js/setTime.js');
                //获取dom对象
                var domMinute_p = document.getElementById('Minute_p');
                var domSecond_p = document.getElementById('Second_p');
                worker.postMessage(600);

                //这里可以接受worker线程的返回值
                worker.onmessage = function(event) {
                    var totalSecond = event.data;
                    console.log(totalSecond)
                    //计算分钟数
                    var minute_p = parseInt(totalSecond / 60);
                    domMinute_p.innerText = minute_p;
                    //计算秒数
                    var second_p = parseInt(totalSecond % 60);
                    domSecond_p.innerText = second_p;
                }
            }
            //这里是模拟的耗时操作
            function business() {
                var data = [1, 2, 3, 4, 5];
                for(var i = 1; i < 1000; i++) {
                    for(var j = 1; j < 1000; j++) {
                        for(var k = 1; k < 5000; k++) {
                            var b = k * 100;
                        }
                    }
                }
                console.log("业务终于走完了!")
            }

worker线程js代码:

var totalSecond = 600;
var domMinute_p, domSecond_p,

    //接受事件参数
    onmessage = function(e) {
        console.log(e.data)
        domMinute_p = e.data;
    }
var timeId = setInterval(function() {
    totalSecond--;

    if(totalSecond == 0) {
        self.close();
    }
    console.log(totalSecond)
    postMessage(totalSecond)

}, 1000)

好了大致示例就是这么多。下面是截图效果:

9159.com 2

 开始运行后编号1会开始倒计时,但是当你点击了编号2进行了模拟耗时后,编号1还是会卡住,只有完成编号2后才会运行,但是不同与上面说到的单线程是,他再次运行时的时间是正确时间,还是刚才的例子如果是9:57,点击编号2模拟耗时了3秒,耗时完成后编号1会显示9:54而不是单线程的9:57。就说明worker现在在耗时操作的时候是持续运行的,时间卡只不过是主线程的dom操作被卡住了而已(可以把耗时业务也开启worker就不卡住了)。这里只是介绍worker的使用,所有就不纠结这个界面显示的问题。

 

 

在task.js代码中,定义了onmessage事件处理函数,由主线程传入的数据,封装在message对象的data属性中,数据处理完成后,通过postMessage方法完成与主线程通信。在工作线程代码中,onmessage事件和postMessage方法在其全局作用域可以访问。

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

3.worker线程执行流程

通信联系

通过查阅资料,webKit加载并执行worker线程的流程如下图所示

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

9159.com 3

脚本限制

Paste_Image.png

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

  1. worker线程的创建的是异步的

文件限制

代码执行到”var worker = new Worker(task.js’)“时,在内核中构造WebCore::JSWorker对象(JSBbindings层)以及对应的WebCore::Worker对象(WebCore模块),根据初始化的url地址”task.js”发起异步加载的流程;主线程代码不会阻塞在这里等待worker线程去加载、执行指定的脚本文件,而是会立即向下继续执行后面代码。

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

  1. postMessage消息交互由内核调度

2.1 主线程

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

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

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

然后,主线程调用worker.postMessage()方法,向 Worker 发消息。

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

worker.postMessage()方法的参数,就是主线程传给 Worker 的数据。它可以是各种数据类型,包括二进制数据。

接着,主线程通过worker.onmessage指定监听函数,接收子线程发回来的消息。

worker.onmessage = function { console.log('Received message ' + event.data); doSomething(); } function doSomething() { // 执行任务 worker.postMessage('Work done!'); }

上面代码中,事件对象的data属性可以获取 Worker 发来的数据。

Worker 完成任务以后,主线程就可以把它关掉。

worker.terminate();

main.js中,在创建woker线程后,立即调用了postMessage方法传递了数据,在worker线程还没创建完成时,main.js中发出的消息,会先存储在一个临时消息队列中,当异步创建worker线程完成,临时消息队列中的消息数据复制到woker对应的WorkerRunLoop的消息队列中,worker线程开始处理消息。在经过一轮消息来回后,继续通信时, 这个时候因为worker线程已经创建,所以消息会直接添加到WorkerRunLoop的消息队列中;

2.2 Worker 线程

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

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

上面代码中,self代表子线程自身,即子线程的全局对象。因此,等同于下面两种写法。

// 写法一 this.addEventListener('message', function { this.postMessage('You said: ' + e.data); }, false); // 写法二 addEventListener('message', function { postMessage('You said: ' + e.data); }, false);

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

根据主线程发来的数据,Worker 线程可以调用不同的方法,下面是一个例子。

self.addEventListener('message', function { var data = e.data; switch { 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);

上面代码中,self.close()用于在 Worker 内部关闭自身。

4.worker线程数据通讯方式

2.3 Worker 加载脚本

Worker 内部如果要加载其他脚本,有一个专门的方法importScripts()

importScripts('script1.js');

该方法可以同时加载多个脚本。

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

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

2.4 错误处理

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

worker.onerror(function { console.log([ 'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message ].join; // 或者 worker.addEventListener('error', function { // ... });

Worker 内部也可以监听error事件。

主线程与子线程之间也可以交换二进制数据,比如File、Blob、ArrayBuffer等对象,也可以在线程之间发送。但是,用拷贝方式发送二进制数据,会造成性能问题。比如,主线程向子线程发送一个50MB文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript允许主线程把二进制数据直接转移给子线程,转移后主线程无法再使用这些数据,这是为了防止出现多个线程同时修改数据的问题,这种转移数据的方法,叫做Transferable Objects。

2.5 关闭 Worker

使用完毕,为了节省系统资源,必须关闭 Worker。

// 主线程 worker.terminate(); // Worker 线程 self.close();

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

主线程与 Worker 之间也可以交换二进制数据,比如 File、Blob、ArrayBuffer 等类型,也可以在线程之间发送。下面是一个例子。

// 主线程 var uInt8Array = new Uint8Array(new ArrayBuffer; for (var i = 0; i < uInt8Array.length; ++i) { uInt8Array[i] = i * 2; // [0, 2, 4, 6, 8,...] } worker.postMessage(uInt8Array); // Worker 线程 self.onmessage = function { var uInt8Array = e.data; postMessage('Inside worker.js: uInt8Array.toString() = ' + uInt8Array.toString; postMessage('Inside worker.js: uInt8Array.byteLength = ' + uInt8Array.byteLength); };

但是,拷贝方式发送二进制数据,会造成性能问题。比如,主线程向 Worker 发送一个 500MB 文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript 允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做Transferable Objects。这使得主线程可以快速把数据交给 Worker,对于影像处理、声音处理、3D 运算等就非常方便了,不会产生性能负担。

如果要直接转移数据的控制权,就要使用下面的写法。

// Transferable Objects 格式 worker.postMessage(arrayBuffer, [arrayBuffer]); // 例子 var ab = new ArrayBuffer; worker.postMessage;

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

<!DOCTYPE html> <body> <script type="app/worker"> addEventListener('message', function () { postMessage('some message'); }, false); </script> </body> </html>

上面是一段嵌入网页的脚本,注意必须指定<script>标签的type属性是一个浏览器不认识的值,上例是app/worker

然后,读取这一段嵌入页面的脚本,用 Worker 来处理。

var blob = new Blob([document.querySelector('#worker').textContent]); var url = window.URL.createObjectURL; var worker = new Worker; worker.onmessage = function { // e.data === 'some message' };

上面代码中,先将嵌入网页的脚本代码,转成一个二进制对象,然后为这个二进制对象生成 URL,再让 Worker 加载这个 URL。这样就做到了,主线程和 Worker 的代码都在同一个网页上面。

有时,浏览器需要轮询服务器状态,以便第一时间得知状态改变。这个工作可以放在 Worker 里面。

function createWorker { var blob = new Blob([f.toString; var url = window.URL.createObjectURL; var worker = new Worker; return worker; } var pollingWorker = createWorker(function { var cache; function compare { ... }; setInterval(function () { fetch('/my-api-endpoint').then(function { var data = res.json(); if (!compare(data, cache)) { cache = data; self.postMessage; } }) }, 1000) }); pollingWorker.onmessage = function () { // render data } pollingWorker.postMessage;

上面代码中,Worker 每秒钟轮询一次数据,然后跟缓存做比较。如果不一致,就说明服务端有了新的变化,因此就要通知主线程。

Worker 线程内部还能再新建 Worker 线程。下面的例子是将一个计算密集的任务,分配到10个 Worker。

主线程代码如下。

var worker = new Worker('worker.js'); worker.onmessage = function { document.getElementById.textContent = event.data; };

Worker 线程代码如下。

// worker.js // settings var num_workers = 10; var items_per_worker = 1000000; // start the workers var result = 0; var pending_workers = num_workers; for (var i = 0; i < num_workers; i += 1) { var worker = new Worker('core.js'); worker.postMessage(i * items_per_worker); worker.postMessage * items_per_worker); worker.onmessage = storeResult; } // handle the results function storeResult { result += event.data; pending_workers -= 1; if (pending_workers <= 0) postMessage; // finished! }

上面代码中,Worker 线程内部新建了10个 Worker 线程,并且依次向这10个 Worker 发送消息,告知了计算的起点和终点。计算任务脚本的代码如下。

// core.js var start; onmessage = getStart; function getStart { start = event.data; onmessage = getEnd; } var end; function getEnd { end = event.data; onmessage = null; work(); } function work() { var result = 0; for (var i = start; i < end; i += 1) { // perform some complex calculation here result += 1; } postMessage; close(); }

// Create a 32MB "file" and fill it.
var uInt8Array = new Uint8Array(1024*1024*32); // 32MB
for (var i = 0; i < uInt8Array .length; ++i) {
  uInt8Array[i] = i;
}
worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);

7.1 主线程

浏览器原生提供Worker()构造函数,用来供主线程生成 Worker 线程。

var myWorker = new Worker(jsUrl, options);

Worker()构造函数,可以接受两个参数。第一个参数是脚本的网址,该参数是必需的,且只能加载 JS 脚本,否则会报错。第二个参数是配置对象,该对象可选。它的一个作用就是指定 Worker 的名称,用来区分多个 Worker 线程。

// 主线程 var myWorker = new Worker('worker.js', { name : 'myWorker' }); // Worker 线程 self.name // myWorker

Worker()构造函数返回一个 Worker 线程对象,用来供主线程操作 Worker。Worker 线程对象的属性和方法如下。

  • Worker.onerror:指定 error 事件的监听函数。
  • Worker.onmessage:指定 message 事件的监听函数,发送过来的数据在Event.data属性中。
  • Worker.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
  • Worker.postMessage():向 Worker 线程发送消息。
  • Worker.terminate():立即终止 Worker 线程。

5.API进阶

7.2 Worker 线程

Web Worker 有自己的全局对象,不是主线程的window,而是一个专门为 Worker 定制的全局对象。因此定义在window上面的对象和方法不是全部都可以使用。

Worker 线程有一些自己的全局属性和方法。

  • self.name: Worker 的名字。该属性只读,由构造函数指定。
  • self.onmessage:指定message事件的监听函数。
  • self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
  • self.close():关闭 Worker 线程。
  • self.postMessage():向产生这个 Worker 线程发送消息。
  • self.importScripts():加载 JS 脚本。

此文已由作者授权腾讯云+社区发布

在worker线程中,可以获得下列对象

  1. navigator对象

  2. location对象,只读

  3. XMLHttpRequest对象

  4. setTimeout/setInterval方法

  5. Application Cache

  6. 通过importScripts()方法加载其他脚本

  7. 创建新的Web Worker

worker线程不能获得下列对象

  1. DOM对象

  2. window对象

  3. document对象

  4. parent对象

上述的规范,限制了在worker线程中获得主线程页面相关对象的能力,所以在worker线程中,不能进行dom元素的更新。

本文由9159.com发布于前端,转载请注明出处:1.上面的例子最好放到服务器上运行,线程完成计

关键词:

上一篇:没有了
下一篇:原文出处,怎么去设计一个组件封装