您的位置:新葡亰496net > 新葡亰官网 > 新葡亰496net:Worker异步施行,起始运用Web

新葡亰496net:Worker异步施行,起始运用Web

发布时间:2019-07-05 08:41编辑:新葡亰官网浏览(80)

    开始使用Web Workers

    2012/11/28 · HTML5, JavaScript · 来源: 伯乐在线     · HTML5, Javascript

    英文原文:tutsplus,编译:伯乐在线 – 胡蓉(@蓉Flora)

    单线程(Single-threaded)运行是JavaScript语言的设计目标之一,进而言之是保持JavaScript的简单。但是我必须要说,尽管JavaScript具有如此语言特质,但它绝不简单!我们所说的“单线程”是指JavaScript只有一个线程控制。是的,这点令人沮丧,JavaScript引擎一次只能做一件事。

    “web workers处在一个严格的无DOM访问的环境里,因为DOM是非线程安全的。”

    现在,你是不是觉得要想利用下你机器闲置的多核处理器太受限制?不用担心,HTML5将改变这一切。

    JavaScript的单线程模式

    有学派认为JavaScript的单线程特质是一种简化,然而也有人认为这是一种限制。后者提出的是一个很好的观点,尤其是现在web应用程序大量的使用JavaScript来处理界面事件、轮询服务端接口、处理大量的数据以及基于服务端的响应操作DOM。

    在维护响应式界面的同时,通过单线程控制处理如此多事件是项艰巨的任务。它迫使开发人员不得不依靠一些技巧或采用变通的方法(如使用setTimeout(),setInterval(),或调用XMLHttpRequest和DOM事件)来实现并发。然而,尽管这些技巧毫无疑问地提供了解决异步调用的方法,但非阻塞的并不意味着是并发的。John Resig在他的博客中解释了为什么不能并行运行。

    限制

    如果你已经和JavaScript打过一段时间的交道,那么你一定也遭遇过如下令人讨厌的对话框,提示你有脚本无响应。没错,几乎大多数的页面无响应都是由JavaScript代码引起的。

    新葡亰496net 1

    以下是一些运行脚本时造成浏览器无响应的原因:

    • 过多的DOM操作:DOM操作也许是在JavaScript运行中代价最高的。所以,大批量的DOM操作无疑是你代码重构的最佳方向之一。
    • 无终止循环:审视你代码中复杂的嵌套循环永远不是坏事。复杂的嵌套循环所做的工作常常比实际需要做的多很多,也许你可以找到其他方法来实现同样的功能。
    • 同时包含以上两种:最坏的情况就是明明有更优雅的办法,却还是在循环中不断更新DOM元素,比如可以采用DocumentFragment。

     

    点评:HTML5 中的 Web Worker 可以分为两种不同线程类型,一个是专用线程 Dedicated Worker,一个是共享线程 Shared Worker。两种类型的线程各有不同的用途,感兴趣的朋友可以了解下啊,或许对你有所帮助

    Javascript执行机制       在HTML5之前,浏览器中JavaScript的运行都是以单线程的方式工作的,虽然有多种方式实现了对多线程的模拟(例如:Javascript 中的 setinterval 方法,setTimeout 方法等),但是在本质上程序的运行仍然是由 JavaScript 引擎以单线程调度的方式进行的。在 HTML5 中引入的工作线程使得浏览器端的 Javascript 引擎可以并发地执行 Javascript 代码,从而实现了对浏览器端多线程编程的良好支持。

    Javascript执行机制       在HTML5之前,浏览器中JavaScript的运行都是以单线程的方式工作的,虽然有多种方式实现了对多线程的模拟(例如:Javascript 中的 setinterval 方法,setTimeout 方法等),但是在本质上程序的运行仍然是由 JavaScript 引擎以单线程调度的方式进行的。在 HTML5 中引入的工作线程使得浏览器端的 Javascript 引擎可以并发地执行 Javascript 代码,从而实现了对浏览器端多线程编程的良好支持。

    在HTML5中提出了工作线程(Web Workers)的概念,即多线程概念,可以将一些大量计算的代码交给web worker运行而不冻结用户界面。

    好帮手Web Workers

    幸好有了HTML5和Web Workers,你可以真正生成一条异步的线程。当主线程处理界面事件时,新的worker可以在后台运行,它甚至可以有力的处理大量的数据。例如,一个worker可以处理大型的数据结构(如JSON),从中提取变量信息然后在界面中显示。好了,废话不多说,让我们看一些实际的代码吧。

     

    创建一个Worker

    通常,与web worker相关的代码都放在一个独立的JavaScript文件中。父线程通过在Worker构造函数中指定一个JavaScript文件的链接来创建一个新的worker,它会异步加载并执行这个JavaScript文件。

    JavaScript

    var primeWorker = new Worker('prime.js');

    1
    var primeWorker = new Worker('prime.js');

     

    启动Worker

    要启动一个Worker,则父线程向worker传递一个信息,如下所示:

    JavaScript

    var current = $('#prime').attr('value'); primeWorker.postMessage(current);

    1
    2
    var current = $('#prime').attr('value');
    primeWorker.postMessage(current);

    父页面可以通过postMessage接口与worker进行通信,这也是跨源通信(cross-origin messaging)的一种方式。通过postMessage接口除了可以向worker传递私有数据类型,它还支持JSON数据结构。但是,你不能传递函数,因为函数也许会包含对潜在DOM的引用。

    “父线程和worker线程有它们各自的独立空间,信息主要是来回交换而不是共享。”

    信息在后台运行时,先在worker端序列化,然后在接收端反序列化。鉴于此,不推荐向worker发送大量的数据。

    父线程同样可以声明一个回调函数,来侦听worker完成任务后发回的消息。这样,父线程就可以在worker完成任务后采取些必要的行动,比如更新DOM元素。如下代码所示:

    JavaScript

    primeWorker.addEventListener('message', function(event){ console.log('Receiving from Worker: ' event.data); $('#prime').html( event.data ); });

    1
    2
    3
    4
    primeWorker.addEventListener('message', function(event){
        console.log('Receiving from Worker: ' event.data);
        $('#prime').html( event.data );
    });

    event对象包含两个重要属性:

    • target:用来指向发送信息的worker,在多元worker环境下比较有用。
    • data:由worker发回给父线程的数据。

    worker本身是包含在prime.js文件中的,它同时侦听message事件,从父线程中接收信息。它同样通过postMessage接口与父线程进行通信。

    JavaScript

    self.addEventListener('message', function(event){ var currPrime = event.data, nextPrime; setInterval( function(){ nextPrime = getNextPrime(currPrime); postMessage(nextPrime); currPrime = nextPrime; }, 500); });

    1
    2
    3
    4
    5
    6
    7
    8
    self.addEventListener('message',  function(event){
        var currPrime = event.data, nextPrime;
        setInterval( function(){
        nextPrime = getNextPrime(currPrime);
        postMessage(nextPrime);
        currPrime = nextPrime;
        }, 500);
    });

    在本文例子中,我们寻找下一个最大的质数,然后不断将结果发回至父线程,同时不断更新界面以显示新的值。在worker的代码中,字段self和this都是指向全局作用域。Worker既可以添加事件侦听器来侦听message事件,也可以定义一个onmessage处理器,来接收从父线程发回的消息。

    寻找下一个质数的例子显然不是worker的理想用例,但是在此选用这个例子是为了说明消息传递的原理。之后,我们会挖掘些可以通过web worker获得益处的实际用例。

     

    终止Workers

    worker属于占用资源密集型,它们属于系统层面的线程。因此,你应该不希望创建太多的worker线程,所以你需要在它完成任务后终止它。Worker可以通过如下方式由自己终止:

    JavaScript

    self.close();

    1
    self.close();

    或者,由父线程终止。

    JavaScript

    primeWorker.terminate();

    1
    primeWorker.terminate();

     

    安全与限制

    在worker的代码中,不要访问一些重要的JavaScript对象,如document、window、console、parent,更重要的是不要访问DOM对象。也许不用DOM元素以至不能更新页面元素听上去有点严格,但是这是一个重要的安全设计决定。

    想象一下,如果众多线程都试着去更新同一个元素那就是个灾难。所以,web worker需要处在一个严格的并线程安全的环境中。

    正如之前所说,你可以通过worker处理数据,并将结果返回主线程,进而更新DOM元素。尽管它们不能访问一些重要的JavaScript对象,但是它们可以调用一些函数,如setTimeout()/clearTimeout()、setInterval()/clearInterval()、navigator等等,也可以访问XMLHttpRequest和localStorge对象。

     

    同源限制

    为了能和服务器交互,worker必须遵守同源策略(same-origin policy)(译注:可参考国人文章同源策略)。比如,位于

     

    Google Chrome与本地访问

    Google Chrome对worker本地访问做了限制,因此你无法本地运行这些例子。如果你又想用Chrome,那么你可以将文件放到服务器上,或者在通过命令启动Chrome时加上–allow-file-access-from-files。例如,苹果系统下:

    $ /Applications/Google Chrome.app/Contents/MacOS/Google Chrome –allow-file-access-from-files

    然而,在实际产品生产过程中,此方法并不推荐。最好还是将你的文件上传至服务器中,同时进行跨浏览器测试。

     

    Worker调试和错误处理

    不能访问console似乎有点不方便,但幸亏有了Chrome开发者工具,你可以像调试其他JavaScript代码那样调试worker。

    新葡亰496net 2

    为处理web worker抛出的异常,你可以侦听error事件,它属于ErrorEvent对象。检测该对象从中了解引起错误的详细信息。

    JavaScript

    primeWorker.addEventListener('error', function(error){ console.log(' Error Caused by worker: ' error.filename ' at line number: ' error.lineno ' Detailed Message: ' error.message); });

    1
    2
    3
    4
    5
    primeWorker.addEventListener('error', function(error){
        console.log(' Error Caused by worker: ' error.filename
             ' at line number: ' error.lineno
             ' Detailed Message: ' error.message);
    });

    多个Worker线程

    尽管创建多个worker来协调任务分配也许很常见,但还是要提醒一下各位,官方规范指出worker属于相对重量级并能长期运行在后台的脚本。所以,由于Web worker的高启动性能成本和高进程内存成本,它们的数量不宜过多。

     

    简单介绍共享workers

    官方规范指出有两种worker:专用线程(dedicated worker)和共享线程(shared worker)。到目前为止,我们只列举了专用线程的例子。专用线程与创建线程的脚本或页面直接关联,即有着一对一的联系。而共享线程允许线程在同源中的多个页面间进行共享,例如:同源中所有页面或脚本可以与同一个共享线程通信。

    “创建一个共享线程,直接将脚本的URL或worker的名字传入SharedWorker构造函数”

    两者最主要的区别在于,共享worker与端口相关联,以保证父脚本或页面可以访问。如下代码创建了一个共享worker,并声明了一个回调函数以侦听worker发回的消息 ,同时向共享worker传输一条消息。

    JavaScript

    var sharedWorker = new SharedWorker('findPrime.js'); sharedWorker.port.onmessage = function(event){ ... } sharedWorker.port.postMessage('data you want to send');

    1
    2
    3
    4
    5
    var sharedWorker = new SharedWorker('findPrime.js');
    sharedWorker.port.onmessage = function(event){
        ...
    }
    sharedWorker.port.postMessage('data you want to send');

    同样,worker可以侦听connect事件,当有客户端想与worker进行连接时会相应地向其发送消息。

    JavaScript

    onconnect = function(event) { // event.source包含对客户端端口的引用 var clientPort = event.source; // 侦听该客户端发来的消息 clientPort.onmessage = function(event) { // event.data包含客户端发来的消息 var data = event.data; .... // 处理完成后发出消息 clientPort.postMessage('processed data'); } };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    onconnect = function(event) {
        // event.source包含对客户端端口的引用
        var clientPort = event.source;
        // 侦听该客户端发来的消息
        clientPort.onmessage = function(event) {
            // event.data包含客户端发来的消息
            var data = event.data;
            ....
            // 处理完成后发出消息
            clientPort.postMessage('processed data');
        }
    };

    由于它们具有共享的属性,你可以保持一个应用程序在不同窗口内的相同状态,并且不同窗口的页面通过同一共享worker脚本保持和报告状态。想更多的了解共享worker,我建议你阅读官方文档。

     

    实际应用场景

    worker的实际发生场景可能是,你需要处理一个同步的第三方接口,于是主线程需要等待结果再进行下一步操作。这种情况下,你可以生成一个worker,由它代理,异步完成此任务。

    Web worker在轮询情况下也非常适用,你可以在后台不断查询目标,并在有新数据时向主线程发送消息。

    你也许遇到需要向服务端返回大量的数据的情况。通常,处理大量数据会消极影响程序的响应能力,然后导致不良用户体验。更优雅的办法是将处理工作分配给若干worker,由它们处理不重叠的数据。

    还有应用场景会出现在通过多个web worker分析音频或视频的来源,每个worker针对专项问题。

     

    结论

    随着HTML5的展开,web worker规范也会持续加入。如果你打算使用web worker,看一看它的官方文档不是坏事。

    专项线程的跨浏览器支持目前还不错,Chrome,Safari和Firefox目前的版本都支持,甚至IE这次都没有落后太多,IE10还是不错的。但是共享线程只有当前版本的Chrome和Safari支持。另外奇怪的一点是,Android 2.1的浏览器支持web worker,反而4.0版本不支持。苹果也从iOS 5.0开始支持web worker。

    想象一下,在原本单线程环境下,多线程会带来无限可能哦~

     

    译注:本人对此JavaScript技术领域并不是特别熟悉,如有误翻的地方,请大家及时批评指正,我将及时修改!!!最后,推荐两篇相关国人优秀文章

    《HTML5 web worker的使用 》

    《深入HTML5 Web Worker应用实践:多线程编程》

     

     

    英文原文:tutsplus,编译:伯乐在线 – 胡蓉(@蓉Flora)

    文章链接:

    【如需转载,请在正文中标注并保留原文链接、译文链接和译者等信息,谢谢合作!】

     

    赞 1 收藏 评论

    Javascript执行机制
    在HTML5之前,浏览器中JavaScript的运行都是以单线程的方式工作的,虽然有多种方式实现了对多线程的模拟(例如:Javascript 中的 setinterval 方法,setTimeout 方法等),但是在本质上程序的运行仍然是由 JavaScript 引擎以单线程调度的方式进行的。在 HTML5 中引入的工作线程使得浏览器端的 Javascript 引擎可以并发地执行 Javascript 代码,从而实现了对浏览器端多线程编程的良好支持。

    Javascript中的多线程 - WebWorker       HTML5 中的 Web Worker 可以分为两种不同线程类型,一个是专用线程 Dedicated Worker,一个是共享线程 Shared Worker。两种类型的线程各有不同的用途。

    Javascript中的多线程 - WebWorker       HTML5 中的 Web Worker 可以分为两种不同线程类型,一个是专用线程 Dedicated Worker,一个是共享线程 Shared Worker。两种类型的线程各有不同的用途。

    Web Workers 的三大主要特征:
    1)能够长时间运行(响应)
    2)理想的启动性能
    3)理想的内存消耗

    关于作者:胡蓉

    新葡亰496net 3

    胡蓉:某互联网公司交互设计师。在这么一个梦想者云集的互联网乐土中,用心培育着属于自己的那一片天地。做自己热爱的,然后一直坚持下去~(新浪微博:@蓉Flora) 个人主页 · 我的文章

    新葡亰496net 4

    新葡亰496net:Worker异步施行,起始运用Web。Javascript中的多线程 - WebWorker HTML5 中的 Web Worker 可以分为两种不同线程类型,一个是专用线程 Dedicated Worker,一个是共享线程 Shared Worker。两种类型的线程各有不同的用途。
    专用型web worker
    专用型worker与创建它的脚本连接在一起,它可以与其他的worker或是浏览器组件通信,但是他不能与DOM通信。专用的含义,我想就是这个线程一次只处理一个需求。专用线程在除了IE外的各种主流浏览器中都实现了,可以放心使用。
    创建线程
    创建worker很简单,只要把需要在线程中执行的JavaScript文件的文件名传给构造函数就可以了。
    线程通信
    在主线程与子线程间进行通信,使用的是线程对象的postMessage和onmessage方法。不管是谁向谁发数据,发送发使用的都是postMessage方法,接收方都是使用onmessage方法接收数据。postMessage只有一个参数,那就是传递的数据,onmessage也只有一个参数,假设为event,则通过event.data获取收到的数据。
    发送JSON数据
    JSON是JS原生支持的东西,不用白不用,复杂的数据就用JSON传送吧。例如:

    专用型web worker

    专用型web worker

    Web Workers允许开发人员编写能够长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的及时响应。

    代码如下:

      专用型worker与创建它的脚本连接在一起,它可以与其他的worker或是浏览器组件通信,但是他不能与DOM通信。专用的含义,就是这个线程一次只处理一个需求。专用线程在除了IE外的各种主流浏览器中都实现了,可以放心使用。
    创建线程
          创建worker很简单,只要把需要在线程中执行的JavaScript文件的文件名传给构造函数就可以了。

      专用型worker与创建它的脚本连接在一起,它可以与其他的worker或是浏览器组件通信,但是他不能与DOM通信。专用的含义,我想就是这个线程一次只处理一个需求。专用线程在除了IE外的各种主流浏览器中都实现了,可以放心使用。
    创建线程       创建worker很简单,只要把需要在线程中执行的JavaScript文件的文件名传给构造函数就可以了。

    Web Workers为
    Web前端网页上的脚本提供了一种能在后台进程中运行的方法。一旦它被创建,Web Workers就可以通过
    postMessage向任务池发送任务请求,执行完之后再通过postMessage返回消息给创建者指定的事件处理程序( 通过 onmessage
    进行捕获 )。Web
    Workers进程能够在不影响用户界面的情况下处理任务,并且,它还可以使用XMLHttpRequest来处理I/O,但通常,后台进程(包括
    Web Workers 进程)不能对DOM进行操作。如果希望后台程序处理的结果能够改变DOM,只能通过返回消息给创建者的回调函数进行处理。

    postMessage({'cmd': 'init', 'timestamp': Date.now()});

    线程通信
          在主线程与子线程间进行通信,使用的是线程对象的postMessage和onmessage方法。不管是谁向谁发数据,发送发使用的都是postMessage方法,接收方都是使用onmessage方法接收数据。postMessage只有一个参数,那就是传递的数据,onmessage也只有一个参数,假设为event,则通过event.data获取收到的数据。

    线程通信
    新葡亰496net:Worker异步施行,起始运用Web。      在主线程与子线程间进行通信,使用的是线程对象的postMessage和onmessage方法。不管是谁向谁发数据,发送发使用的都是postMessage方法,接收方都是使用onmessage方法接收数据。postMessage只有一个参数,那就是传递的数据,onmessage也只有一个参数,假设为event,则通过event.data获取收到的数据。

    需要在客户端页面的JavaScript代码中new
    一个Worker实例出来,参数是需要在另一个线程中运行的JavaScript文件名称。然后在这个实例上监听onmessage事件。最后另一个线程中的JavaScript就可以通过调用postMessage方法在这两个线程间传递数据了。

    处理错误
    当线程发生错误的时候,它的onerror事件回调会被调用。所以处理错误的方式很简单,就是挂接线程实例的onerror事件。这个回调函数有一个参数error,这个参数有3个字段:message

    发送JSON数据
          JSON是JS原生支持的东西,不用白不用,复杂的数据就用JSON传送吧。例如:

    发送JSON数据       JSON是JS原生支持的东西,不用白不用,复杂的数据就用JSON传送吧。例如:

    **主程序中,创建worker实例,监听onmessage事件 **

    • 错误消息;filename - 发生错误的脚本文件;lineno - 发生错误的行。
      销毁线程
      在线程内部,使用close方法线程自己销毁自己。在线程外部的主线程中,使用线程实例的terminate方法销毁线程。
      下面从一个例子看线程的基本操作:
      HTML代码:

    postMessage({'cmd': 'init', 'timestamp': Date.now()});

    postMessage({'cmd': 'init', 'timestamp': Date.now()});

    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Test Web worker</title>
    <script type="text/JavaScript">
    function init(){
    var worker = new Worker('compute.js');
    //event 参数中有data属性,就是子线程中返回的结果数据
    worker.onmessage= function (event) {
    // 把子线程返回的结果添加到 div 上
    document.getElementById("result").innerHTML =
    event.data "
    ";
    };
    }
    </script>
    </head>
    <body onload="init()">
    <div id="result"></div>
    </body>
    </html>

    代码如下:

    处理错误
          当线程发生错误的时候,它的onerror事件回调会被调用。所以处理错误的方式很简单,就是挂接线程实例的onerror事件。这个回调函数有一个参数error,这个参数有3个字段:message

    处理错误       当线程发生错误的时候,它的onerror事件回调会被调用。所以处理错误的方式很简单,就是挂接线程实例的onerror事件。这个回调函数有一个参数error,这个参数有3个字段:message

    在客户端的compute.js开辟了一个新的线程,不起阻塞执行的效果,并且提供主线程和新线程之间的数据交互接口。只是简单的重复多次加和操作,最后通过postMessage方法把结果返回给主线程,目的就是等待一段时间。而在这段时间内,主线程不应该被阻塞,用户可以通过拖拽浏览器,变大缩小浏览器窗口等操作测试这一现象。这个非阻塞主线程的结果就是Web
    Workers想达到的目的。

    <!DOCTYPE HTML>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>web worker fibonacci</title>
    <script type="text/javascript">
    onload = function(){
    var worker = new Worker('fibonacci.js');
    worker.onmessage = function(event) {
    console.log("Result:" event.data);
    };
    worker.onerror = function(error) {
    console.log("Error:" error.message);
    };
    worker.postMessage(40);
    }
    </script>
    </head>
    <body>
    </body>
    </html>

    • 错误消息;filename - 发生错误的脚本文件;lineno - 发生错误的行。
    • 错误消息;filename - 发生错误的脚本文件;lineno - 发生错误的行。

    **
    compute.js 中调用 postMessage 方法返回计算结果**
    var i=0;

    脚本文件fibonacci.js代码:

    销毁线程
          在线程内部,使用close方法线程自己销毁自己。在线程外部的主线程中,使用线程实例的terminate方法销毁线程。

    销毁线程       在线程内部,使用close方法线程自己销毁自己。在线程外部的主线程中,使用线程实例的terminate方法销毁线程。

    function timedCount(){
    for(var j=0,sum=0;j<100;j ){
    for(var i=0;i<1000000;i ){
    sum =i;
    }
    }
    // 调用 postMessage 向主线程发送消息
    postMessage(sum);
    }

    代码如下:

    HTML代码:

    下面从一个例子看线程的基本操作:
    HTML代码:

    postMessage("获取计算之前的时间," new Date());
    timedCount();
    postMessage("获取计算之后的时间," new Date());

    //fibonacci.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));
    };

    <script type="text/javascript">
      onload = function(){
          var worker = new Worker('fibonacci.js');  
          worker.onmessage = function(event) {
            console.log("Result:"   event.data);
          };
          worker.onerror = function(error) {
            console.log("Error:"   error.message);
          };
          worker.postMessage(40);
      }  
      </script>
    脚本文件fibonacci.js代码:

    <!DOCTYPE HTML>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>web worker fibonacci</title>
    <script type="text/javascript">
      onload = function(){
          var worker = new Worker('fibonacci.js');  
          worker.onmessage = function(event) {
            console.log("Result:"   event.data);
          };
          worker.onerror = function(error) {
            console.log("Error:"   error.message);
          };
          worker.postMessage(40);
      }  
      </script>
    </head>
    <body>
    </body>
    </html>

    由于javascript是单线程执行的,在复杂地运算的过程中浏览器不能执行其它javascript脚本,UI渲染线程也会被挂起,从而导致浏览器进入僵死状态。使用web worker将数列的计算过程放入一个新线程里去执行将避免这种情况的出现。

    把它们放到相同的目录,运行页面文件,查看控制台,可以看到运行的结果。
    这里还有一点,在主线程中,onmessage事件可以使用另外一种方式挂接:

    //fibonacci.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));
    };

    脚本文件fibonacci.js代码:

    除了可以使用web
    worker加载一个JS进行大量的复杂计算而不挂起主进程,并通过postMessage,onmessage进行通信外;可以在worker中通过importScripts(url)加载另外的脚本文件,使用
    setTimeout(), clearTimeout(), setInterval(), and
    clearInterval(),使用XMLHttpRequest来发送请求,访问navigator的部分属性。

    代码如下:

    把它们放到相同的目录,运行页面文件,查看控制台,可以看到运行的结果。
    这里还有一点,在主线程中,onmessage事件可以使用另外一种方式挂接:

    //fibonacci.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));
    };

    但是也是存在一定的局限性:
    1.不能跨域加载JS(同源策略限制)
    2.worker内代码不能访问DOM
    3.各个浏览器对Worker的实现不大一致
    4.不是每个浏览器都支持这个新特性

    worker.addEventListener('message', function(event) {
    console.log("Result:" event.data);
    }, false);

    worker.addEventListener('message', function(event) {
       console.log("Result:"   event.data);
    }, false);

    把它们放到相同的目录,运行页面文件,查看控制台,可以看到运行的结果。
    这里还有一点,在主线程中,onmessage事件可以使用另外一种方式挂接:

    个人觉得很麻烦,不如用onmessage直接。
    使用其他脚本文件
    工作线程可以使用全局方法importScripts来加载和使用其他的域内脚本文件或者类库。例如下面都是合法的使用方式:

    个人觉得很麻烦,不如用onmessage直接。

    worker.addEventListener('message', function(event) {
       console.log("Result:"   event.data);
    }, false);

    代码如下:

    使用其他脚本文件
          工作线程可以使用全局方法importScripts来加载和使用其他的域内脚本文件或者类库。例如下面都是合法的使用方式:

    个人觉得很麻烦,不如用onmessage直接。

    importScripts();/* imports nothing */
    importScripts('foo.js'); /* imports just "foo.js" */
    importScripts('foo.js', 'bar.js');/* imports two scripts */

    importScripts();                        
    importScripts('foo.js');                
    importScripts('foo.js', 'bar.js');      

    使用其他脚本文件       工作线程可以使用全局方法importScripts来加载和使用其他的域内脚本文件或者类库。例如下面都是合法的使用方式:

    导入以后,可以直接使用这些文件中的方法。看一个网上的小例子:

          导入以后,可以直接使用这些文件中的方法。看一个网上的小例子:

    importScripts();                        /* imports nothing */
    importScripts('foo.js');                /* imports just "foo.js" */
    importScripts('foo.js', 'bar.js');      /* imports two scripts */

    代码如下:

     
     importScripts('math_utilities.js'); 
     
     onmessage = function (event) 
     { 
       var first = event.data.first; 
       var second = event.data.second; 
       calculate(first,second); 
     }; 
     
     function calculate(first,second) { 
        //do the calculation work 
       var common_divisor=divisor(first,second); 
       var common_multiple=multiple(first,second); 
       postMessage("Work done! "   
          "The least common multiple is " common_divisor  

          导入以后,可以直接使用这些文件中的方法。看一个网上的小例子:

    /**
    * 使用 importScripts 方法引入外部资源脚本,在这里我们使用了数学公式计算工具库 math_utilities.js
    * 当 JavaScript 引擎对这个资源文件加载完毕后,继续执行下面的代码。同时,下面的的代码可以访问和调用
    * 在资源文件中定义的变量和方法。
    **/
    importScripts('math_utilities.js');
    onmessage = function (event)
    {
    var first = event.data.first;
    var second = event.data.second;
    calculate(first,second);
    };
    function calculate(first,second) {
    //do the calculation work
    var common_divisor=divisor(first,second);
    var common_multiple=multiple(first,second);
    postMessage("Work done! "
    "The least common multiple is " common_divisor
    " and the greatest common divisor is " common_multiple);
    }

          " and the greatest common divisor is " common_multiple); 
     } 

    /** 
     * 使用 importScripts 方法引入外部资源脚本,在这里我们使用了数学公式计算工具库 math_utilities.js 
     * 当 JavaScript 引擎对这个资源文件加载完毕后,继续执行下面的代码。同时,下面的的代码可以访问和调用
     * 在资源文件中定义的变量和方法。
     **/ 
     importScripts('math_utilities.js'); 
     
     onmessage = function (event) 
     { 
       var first = event.data.first; 
       var second = event.data.second; 
       calculate(first,second); 
     }; 
     
     function calculate(first,second) { 
        //do the calculation work 
       var common_divisor=divisor(first,second); 
       var common_multiple=multiple(first,second); 
       postMessage("Work done! "   
          "The least common multiple is " common_divisor 

    网上也有网友想到了利用这里的importScripts方法解决资源预加载的问题(浏览器预先加载资源,而不会对资源进行解析和执行),道理也很简单。
    线程嵌套
    在工作线程中还可以在创建子线程,各种操作还是一样的。
    同步问题
    Worker没有锁的机制,多线程的同步问题只能靠代码来解决(比如定义信号变量)。
    共享型SharedWebWorker 共享型web worker主要适用于多连接并发的问题。因为要处理多连接,所以它的API与专用型worker稍微有点区别。除了这一点,共享型web worker和专用型worker一样,不能访问DOM,并且对窗体属性的访问也受到限制。共享型web worker也不能跨越通信。
    页面脚本可以与共享型web worker通信,然而,与专用型web worker(使用了一个隐式的端口通信)稍微有点不同的是,通信是显式的通过使用一个端口(port)对象并附加上一个消息事件处理程序来进行的。
    在收到web worker脚本的首个消息之后,共享型web worker把一个事件处理程序附加到激活的端口上。一般情况下,处理程序会运行自己的postMessage()方法来把一个消息返回给调用代码,接着端口的start()方法生成一个有效的消息进程。
    看网上能找到的的唯一个例子:创建一个共享线程用于接收从不同连接发送过来的指令,然后实现自己的指令处理逻辑,指令处理完成后将结果返回到各个不同的连接用户。
    HTML代码:

          网上也有网友想到了利用这里的importScripts方法解决资源预加载的问题(浏览器预先加载资源,而不会对资源进行解析和执行),道理也很简单。

          " and the greatest common divisor is " common_multiple); 
     } 

    代码如下:

     

          网上也有网友想到了利用这里的importScripts方法解决资源预加载的问题(浏览器预先加载资源,而不会对资源进行解析和执行),道理也很简单。

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Shared worker example: how to use shared worker in HTML5</title>
    <script>
    var worker = new SharedWorker('sharedworker.js');
    var log = document.getElementById('response_from_worker');
    worker.port.addEventListener('message', function(e) {
    //log the response data in web page
    log.textContent =e.data;
    }, false);
    worker.port.start();
    worker.port.postMessage('ping from user web page..');
    //following method will send user input to sharedworker
    function postMessageToSharedWorker(input)
    {
    //define a json object to construct the request
    var instructions={instruction:input.value};
    worker.port.postMessage(instructions);
    }
    </script>
    </head>
    <body onload=''>
    <output id='response_from_worker'>
    Shared worker example: how to use shared worker in HTML5
    </output>
    send instructions to shared worker:
    <input type="text" autofocus oninput="postMessageToSharedWorker(this);return false;">
    </input>
    </body>
    </html>

    线程嵌套
          在工作线程中还可以在创建子线程,各种操作还是一样的。

     

    脚本文件代码:

    同步问题
          Worker没有锁的机制,多线程的同步问题只能靠代码来解决(比如定义信号变量)。

    线程嵌套       在工作线程中还可以在创建子线程,各种操作还是一样的。

    代码如下:

     

    同步问题       Worker没有锁的机制,多线程的同步问题只能靠代码来解决(比如定义信号变量)。

    // 创建一个共享线程用于接收从不同连接发送过来的指令,指令处理完成后将结果返回到各个不同的连接用户。
    var connect_number = 0;
    onconnect = function(e) {
    connect_number =connect_number 1;
    //get the first port here
    var port = e.ports[0];
    port.postMessage('A new connection! The current connection number is '

    共享型SharedWebWorker   共享型web worker主要适用于多连接并发的问题。因为要处理多连接,所以它的API与专用型worker稍微有点区别。除了这一点,共享型web worker和专用型worker一样,不能访问DOM,并且对窗体属性的访问也受到限制。共享型web worker也不能跨越通信。
      页面脚本可以与共享型web worker通信,然而,与专用型web worker(使用了一个隐式的端口通信)稍微有点不同的是,通信是显式的通过使用一个端口(port)对象并附加上一个消息事件处理程序来进行的。

     

    • connect_number);
      port.onmessage = function(e) {
      //get instructions from requester
      var instruction=e.data.instruction;
      var results=execute_instruction(instruction);
      port.postMessage('Request: ' instruction ' Response ' results
      ' from shared worker...');
      };
      };
      /*
      * this function will be used to execute the instructions send from requester
      * @param instruction
      * @return
      */
      function execute_instruction(instruction)
      {
      var result_value;
      //implement your logic here
      //execute the instruction...
      return result_value;
      }

      在收到web worker脚本的首个消息之后,共享型web worker把一个事件处理程序附加到激活的端口上。一般情况下,处理程序会运行自己的postMessage()方法来把一个消息返回给调用代码,接着端口的start()方法生成一个有效的消息进程。
          看网上能找到的的唯一个例子:创建一个共享线程用于接收从不同连接发送过来的指令,然后实现自己的指令处理逻辑,指令处理完成后将结果返回到各个不同的连接用户。
    HTML代码:

    共享型SharedWebWorker   共享型web worker主要适用于多连接并发的问题。因为要处理多连接,所以它的API与专用型worker稍微有点区别。除了这一点,共享型web worker和专用型worker一样,不能访问DOM,并且对窗体属性的访问也受到限制。共享型web worker也不能跨越通信。
      页面脚本可以与共享型web worker通信,然而,与专用型web worker(使用了一个隐式的端口通信)稍微有点不同的是,通信是显式的通过使用一个端口(port)对象并附加上一个消息事件处理程序来进行的。

    在上面的共享线程例子中,在主页面即各个用户连接页面构造出一个共享线程对象,然后定义了一个方法 postMessageToSharedWorker 向共享线程发送来之用户的指令。同时,在共享线程的实现代码片段中定义 connect_number 用来记录连接到这个共享线程的总数。之后,用 onconnect 事件处理器接受来自不同用户的连接,解析它们传递过来的指令。最后,定义一个了方法 execute_instruction 用于执行用户的指令,指令执行完成后将结果返回给各个用户。

    <script> 
      var worker = new SharedWorker('sharedworker.js'); 
      var log = document.getElementByIdx_x_x_x_x('response_from_worker'); 
      worker.port.addEventListener('message', function(e) { 
      //log the response data in web page 
      log.textContent =e.data; 
      }, false); 
      worker.port.start(); 
      worker.port.postMessage('ping from user web page..'); 
      
    新葡亰496net,  //following method will send user input to sharedworker 
      function postMessageToSharedWorker(input) 
      { 
      //define a json object to construct the request 
      var instructions={instruction:input.value}; 
      worker.port.postMessage(instructions); 
      } 
      </script>   

      在收到web worker脚本的首个消息之后,共享型web worker把一个事件处理程序附加到激活的端口上。一般情况下,处理程序会运行自己的postMessage()方法来把一个消息返回给调用代码,接着端口的start()方法生成一个有效的消息进程。
          看网上能找到的的唯一个例子:创建一个共享线程用于接收从不同连接发送过来的指令,然后实现自己的指令处理逻辑,指令处理完成后将结果返回到各个不同的连接用户。
    HTML代码:

    这里我们并没有跟前面的例子一样使用到了工作线程的 onmessage 事件处理器,而是使用了另外一种方式 addEventListener。实际上,前面已经说过,这两种的实现原理基本一致,只是在这里有些稍微的差别,如果使用到了 addEventListener 来接受来自共享线程的消息,那么就要先使用 worker.port.start() 方法来启动这个端口。之后就可以像工作线程的使用方式一样正常的接收和发送消息。
    最后陈述
    线程中能做的事
    1.能使用setTimeout(), clearTimeout(), setInterval(),clearInterval()等函数。
    2.能使用navigator对象。
    3.能使用XMLHttpRequest来发送请求。
    4.可以在线程中使用Web Storage。
    5.线程中可以用self获取本线程的作用域。
    线程中不能做的事
    1.线程中是不能使用除navigator外的DOM/BOM对象,例如window,document(想要操作的话只能发送消息给worker创建者,通过回调函数操作)。
    2.线程中不能使用主线程中的变量和函数。
    3.线程中不能使用有"挂起"效果的操作命令,例如alert等。
    4.线程中不能跨域加载JS。
    线程也是需要消耗资源的,而且使用线程也会带来一定的复杂性,所以如果没有充足的理由来使用额外的线程的话,那么就不要用它。
    实用参考
    官方文档:
    WebWorker分类说明:
    脚本之家:
    WebWorker概述:

     脚本文件代码:

    <!DOCTYPE html> 
     <html> 
     <head> 
     <meta charset="UTF-8"> 
     <title>Shared worker example: how to use shared worker in HTML5</title> 
     
     <script> 
      var worker = new SharedWorker('sharedworker.js'); 
      var log = document.getElementById('response_from_worker'); 
      worker.port.addEventListener('message', function(e) { 
      //log the response data in web page 
      log.textContent =e.data; 
      }, false); 
      worker.port.start(); 
      worker.port.postMessage('ping from user web page..'); 
      
      //following method will send user input to sharedworker 
      function postMessageToSharedWorker(input) 
      { 
      //define a json object to construct the request 
      var instructions={instruction:input.value}; 
      worker.port.postMessage(instructions); 
      } 
     </script> 
     
     </head> 
     <body onload=''> 
     <output id='response_from_worker'> 
       Shared worker example: how to use shared worker in HTML5 
     </output> 
      send instructions to shared worker: 
     <input type="text" autofocus oninput="postMessageToSharedWorker(this);return false;"> 
     </input> 
     </body> 
     </html> 

     // 创建一个共享线程用于接收从不同连接发送过来的指令,指令处理完成后将结果返回到各个不同的连接用户。
     var connect_number = 0; 
     
     onconnect = function(e) { 
      connect_number =connect_number  1; 
      //get the first port here 
      var port = e.ports[0]; 
      port.postMessage('A new connection! The current connection number is ' 
        connect_number); 
      port.onmessage = function(e) { 
       //get instructions from requester 
       var instruction=e.data.instruction; 
       var results=execute_instruction(instruction); 
        port.postMessage('Request: ' instruction ' Response ' results 
           ' from shared worker...'); 
      }; 
     }; 
     function execute_instruction(instruction) 
     { 
     var result_value; 
     //implement your logic here 
     //execute the instruction... 
     return result_value;
     } 

    脚本文件代码:

          在上面的共享线程例子中,在主页面即各个用户连接页面构造出一个共享线程对象,然后定义了一个方法 postMessageToSharedWorker 向共享线程发送来之用户的指令。同时,在共享线程的实现代码片段中定义 connect_number 用来记录连接到这个共享线程的总数。之后,用 onconnect 事件处理器接受来自不同用户的连接,解析它们传递过来的指令。最后,定义一个了方法 execute_instruction 用于执行用户的指令,指令执行完成后将结果返回给各个用户。

     // 创建一个共享线程用于接收从不同连接发送过来的指令,指令处理完成后将结果返回到各个不同的连接用户。
     var connect_number = 0; 
     
     onconnect = function(e) { 
      connect_number =connect_number  1; 
      //get the first port here 
      var port = e.ports[0]; 
      port.postMessage('A new connection! The current connection number is ' 
        connect_number); 
      port.onmessage = function(e) { 
       //get instructions from requester 
       var instruction=e.data.instruction; 
       var results=execute_instruction(instruction); 
        port.postMessage('Request: ' instruction ' Response ' results 
          ' from shared worker...'); 
      }; 
     }; 
     
     /* 
     * this function will be used to execute the instructions send from requester 
     * @param instruction 
     * @return 
     */ 
     function execute_instruction(instruction) 
     { 
     var result_value; 
     //implement your logic here 
     //execute the instruction... 
     return result_value;
     } 

          这里我们并没有跟前面的例子一样使用到了工作线程的 onmessage 事件处理器,而是使用了另外一种方式 addEventListener。实际上,前面已经说过,这两种的实现原理基本一致,只是在这里有些稍微的差别,如果使用到了 addEventListener 来接受来自共享线程的消息,那么就要先使用 worker.port.start() 方法来启动这个端口。之后就可以像工作线程的使用方式一样正常的接收和发送消息。

          在上面的共享线程例子中,在主页面即各个用户连接页面构造出一个共享线程对象,然后定义了一个方法 postMessageToSharedWorker 向共享线程发送来之用户的指令。同时,在共享线程的实现代码片段中定义 connect_number 用来记录连接到这个共享线程的总数。之后,用 onconnect 事件处理器接受来自不同用户的连接,解析它们传递过来的指令。最后,定义一个了方法 execute_instruction 用于执行用户的指令,指令执行完成后将结果返回给各个用户。

     

          这里我们并没有跟前面的例子一样使用到了工作线程的 onmessage 事件处理器,而是使用了另外一种方式 addEventListener。实际上,前面已经说过,这两种的实现原理基本一致,只是在这里有些稍微的差别,如果使用到了 addEventListener 来接受来自共享线程的消息,那么就要先使用 worker.port.start() 方法来启动这个端口。之后就可以像工作线程的使用方式一样正常的接收和发送消息。

    线程中能做的事
    1.能使用setTimeout(), clearTimeout(), setInterval(),clearInterval()等函数。
    2.能使用navigator对象。
    3.能使用XMLHttpRequest来发送请求。
    4.可以在线程中使用Web Storage。

     

    5.线程中可以用self获取本线程的作用域。

    最后陈述

     

    线程中能做的事
    1.能使用setTimeout(), clearTimeout(), setInterval(),clearInterval()等函数。
    2.能使用navigator对象。
    3.能使用XMLHttpRequest来发送请求。
    4.可以在线程中使用Web Storage。

    线程中不能做的事
    1.线程中是不能使用除navigator外的DOM/BOM对象,例如window,document(想要操作的话只能发送消息给worker创建者,通过回调函数操作)。
    2.线程中不能使用主线程中的变量和函数。
    3.线程中不能使用有"挂起"效果的操作命令,例如alert等。
    4.线程中不能跨域加载JS。

    5.线程中可以用self获取本线程的作用域。

     

     

    线程也是需要消耗资源的,而且使用线程也会带来一定的复杂性,所以如果没有充足的理由来使用额外的线程的话,那么就不要用它。

    线程中不能做的事
    1.线程中是不能使用除navigator外的DOM/BOM对象,例如window,document(想要操作的话只能发送消息给worker创建者,通过回调函数操作)。
    2.线程中不能使用主线程中的变量和函数。
    3.线程中不能使用有"挂起"效果的操作命令,例如alert等。
    4.线程中不能跨域加载JS。

     

    线程也是需要消耗资源的,而且使用线程也会带来一定的复杂性,所以如果没有充足的理由来使用额外的线程的话,那么就不要用它。

    实用参考 官方文档:
    WebWorker分类说明:
    WebWorker概述:

    本文由新葡亰496net发布于新葡亰官网,转载请注明出处:新葡亰496net:Worker异步施行,起始运用Web

    关键词: