Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

SharedWorker缺少disconnect事件

  在SharedWorker中只有connect事件,但是却没有disconnect事件,而且即使一个连接已经失效postMessage的调用也不会出错,连接对象上也没有一个用于检测状态的标识符。所以在SharedWorker中无法判断一个连接是否依然存活,是不是需要一个“心跳包”呢?
  其实规范中有个PortCollection,但我觉得这个问题不适合用这玩意儿解决,规范中也说了它目前是存在争议的,而且浏览器也没有实现,所以没法使用。这个问题目前果然还是需要自己实现一个“心跳包”来解决,下面是一个简易的实现,暂时没有封装。
//worker.js
var uid=0;
var pool=[]; //用于存放连接对象
var map={}; //用于记录连接寿命
onconnect=function(e){
  var port=e.ports[0];
  map[port.uid=uid++]=new Date;
  pool.push(port);
  port.onmessage=function(e){
    switch(e.data.name){
      case "message": //收到消息,广播给所有连接
        for(var i=0;i<pool.length;i++)
          pool[i].postMessage({name:"message",value:e.data.value});
        break;
      case "ping": //收到ping包,延续当前连接寿命,并返回pong包
        map[port.uid]=new Date;
        port.postMessage({name:"pong",value:e.data.value});
    };
  };
  port.postMessage({name:"connected"});
};
//从pool中移除掉超时的连接
setInterval(function(){
  for(var i=0;i<pool.length;i++)
    if(Date.now()-map[pool[i].uid]>2000)
      delete map[pool[i].uid],pool.splice(i--,1);
},5000);
<!--test.html-->
<input type="text" id="text" />
<input type="button" id="send" value="发送" />
<script>
var port;
send.onclick=function(){
  port.postMessage({name:"message",value:text.value});
};
(function callee(){
  //连接SharedWorker
  port=new SharedWorker("worker.js").port;
  console.log("connecting...");
  //准备定期发送“心跳包”
  var itv=setInterval(function(){
    port.postMessage({
      name:"ping",value:setTimeout(function(){
        //收不到pong包就重连
        console.log("broken!!");
        clearInterval(itv);
        callee();
      },1000)
    });
    console.log("ping");
  },2000);
  //处理消息
  port.onmessage=function(e){
    switch(e.data.name){
      case "pong": //收到ping的返回包
        clearTimeout(e.data.value);
        console.log("pong");
        break;
      case "connected": //连接成功
        console.log("connected");
        break;
      case "message": //收到消息
        console.log("message: "+e.data.value);
        document.body.insertAdjacentHTML(
          "beforeend","<div>"+e.data.value+"</div>"
        );
        break;
    };
  };
})();
</script>

  这样服务器就可以检测连接的状态,并定期清理掉一些已经失效的连接。但是上面的代码相当混乱,这东西要是没有封装的话估计很难使用。
网名:
3.84.186.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^