zoukankan      html  css  js  c++  java
  • SharedWorkerの簡単な例

    SharedWorker について、仕様にある例は大きすぎて何が起こってるのかつかみにくいので、簡単な例を載せてはどうか、というメールがあったので紹介。

    僕も SharedWorker は例が面倒なので今日までちゃんと読んだことがなかった。


    簡単な順に3段階。


    step 1

    • test.html
     
    <pre id="log">Log:</pre> 
    <script> 
    var worker = new SharedWorker('test.js'); 
    var log = document.getElementById('log'); 
    worker.port.onmessage = function(e) { // note: not worker.onmessage! 
       log.textContent += '\n' + e.data; 
    } 
    </script> 
    
    • test.js
     
    onconnect = function(e) { 
       var port = e.ports[0];
       port.postMessage('hello');
    } 
    

    test.html を開くと test.js が SharedWorker として呼ばれる。

    普通の Worker と違って worker.port.onmessage で通信するらしい。

    test.js のほうで var port = e.ports[0] とやっているのは、MessageChannel のほうに詳しく書いた。

    ただしそこは var port = e.target でもいいらしい。


    step 2

    • test.html
     
    <pre id="log">Log:</pre> 
    <script> 
    var worker = new SharedWorker('test.js'); 
    var log = document.getElementById('log'); 
    worker.port.addEventListener('message', function(e) { 
       log.textContent += '\n' + e.data; 
    }, false); 
    worker.port.start(); // note: need this when using addEventListener 
    worker.port.postMessage('ping'); 
    </script> 
    
    • test.js
     
    onconnect = function(e) { 
       var port = e.ports[0];
       port.postMessage('hello');
       port.onmessage = function(e) { 
         port.postMessage('pong'); // not e.ports[0].postMessage! 
       } 
    } 
    

    worker.port.onmessage をセットすると暗黙の了解で Worker スレッドを走らせてくれるけど、addEventListener('message',..) の場合は start() を明示的に呼んでやらないといけない。

    The first time a MessagePort object's onmessage IDL attribute is set, the port's port message queue must be enabled, as if the start() method had been called.

    http://www.w3.org/TR/html5/comms.html#messageport

    step 3

    • test.html
     
    <pre id="log">Log:</pre> 
    <script> 
    var worker = new SharedWorker('test.js'); 
    var log = document.getElementById('log'); 
    worker.port.addEventListener('message', function(e) { 
       log.textContent += '\n' + e.data; 
    }, false); 
    worker.port.start(); 
    worker.port.postMessage('ping'); 
    </script> 
    <iframe src=other.html></iframe> 
    
    • other.html
     
    <pre id=log>Inner log:</pre> 
    <script> 
    var worker = new SharedWorker('test.js'); 
    var log = document.getElementById('log'); 
    worker.port.onmessage = function(e) { 
       log.textContent += '\n' + e.data; 
    } 
    </script> 
    
    • test.js
     
    var i = 0;
    onconnect = function(e) { 
       i++;
       var port = e.ports[0];
       port.postMessage('hello, ' + i);
       port.onmessage = function(e) { 
         port.postMessage('pong');
       } 
    } 
    

    test.html と other.html から同じ URL の SharedWorker が呼び出され、それらは共有される。どちらかを開いたままもう一方をリロードすると、数字が増えていくはず。


    感想

    何に使えるか。たしか Chrome のドキュメントのどこかで、Gmail のようなアプリケーションでタブを複数開くと、それぞれが独立にサーバーと通信して面倒なことになるので、セッションをまとめる役割で使えるとか読んだ気がする。

    普通の Worker だったら単にグローバルに onmessage = function() ... と書くところを、onconnect = function(e) { e.ports[0].onmessage = ...} として port を自分で収集しないといけないらしい。大変気持ち悪い。

    例えば step 3 の場合、test.html と other.html を両方開いた状態で片方をリロードすると、そのたびに var port = e.ports[0] されて port.onmessage = function(e) { port.postMessage('pong'); } が呼ばれることになるけど、そのぶんのメモリはいつ解放されるんだろう。たぶん全部の親ウィンドウを閉じたときに Worker ごと消える? だったら適当な間隔で port が繋がっているかを監視する必要があると思うんだけど、isConnected のようなプロパティは無いみたいだし、実際に送ってみないと相手が存在するか分からないようになっているっぽい。

    Hixie さん曰く、上のケースでは適切に解放されるらしい。下のケースでは手動で解放しないといけないらしい。

    別の例を考えてみる。以下のような Shared Worker Script があったとして、

     
    var myPorts = [];
     
    onconnect = function(e) { 
      var port = e.ports[0];
      myPorts.push(port);
     
      port.onmessage = function(e) { // あるタブからメッセージを受け取ったら 
        myPorts.forEach(function(p) { 
          if (p !== port)
            p.postMessage(e.data); // 他のすべてのタブに同じメッセージを送る 
        });
      } 
    } 
    

    複数の親タブのうちの一つがリロードされたとする。すると、myPorts がどんどん増えていくことになる。だけど、リロードされる前のタブと繋がっている port は明らかに不要なので、どこかのタイミングで消してあげたい。これを簡単にやる方法は、今のところないっぽい。

    このへんは気が向いたらメールを投げてみようと思う。↓メールした。

查看全文
  • 相关阅读:
    SIP穿越NAT SIP穿越防火墙-SBC
    安卓SAX解析XML文件
    C#进阶系列——WebApi 异常处理解决方案
    C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解
    C#进阶系列——WebApi 接口参数不再困惑:传参详解
    C#进阶系列——WebApi 身份认证解决方案:Basic基础认证
    C#进阶系列——WebApi 跨域问题解决方案:CORS
    C#进阶系列——WebApi 接口测试工具:WebApiTestClient
    微信公众平台向特定用户推送消息
    JSONP跨域的原理解析
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/1715078.html
  • Copyright © 2011-2022 走看看