JavaScript: How to know if a connection with a shared worker is still alive?

我怕爱的太早我们不能终老 提交于 2019-12-20 09:34:56

问题


I'm trying to use a shared worker to maintain a list of all the windows/tabs of a web application. Therefore following code is used:

//lives in shared-worker.js
var connections=[];//this represents the list of all windows/tabs
onconnect=function(e){
  connections.push(e.ports[0]);
};

Everytime a window is created a connection is established with the shared-worker.js worker and the worker adds the connection with the window to the connections list.

When a user closes a window its connection with the shared worker expires and should be removed from the connections variable. But I don't find any reliable way to do that.

Looking at the specification the objects of the connections variable doesn't seem to hold a property/function to check if the connection is still alive.

Is it possible?
Again, the overall goal is to have the list of all windows/tabs.

EDIT: An approach would be to make the shared worker message the windows and expect a reply. If the shared worker doesn't receive a reply then it would assume that the window is closed. In my experiments this approach has not shown to be reliable; the problem being that there is no way to tell if a window is closed or is just taking a long time to reply.


回答1:


This is only as reliable as beforeunload, but seems to work (tested in Firefox and Chrome). I definitely favour it over a polling solution.

// Tell the SharedWorker we're closing
addEventListener( 'beforeunload', function()
{
    port.postMessage( {command:'closing'} );
});

Then handle the cleanup of the port object in the SharedWorker.

e.ports[0].onmessage = function( e )
{
    const port = this,
    data = e.data;

    switch( data.command )
    {
        // Tab closed, remove port
        case 'closing': myConnections.splice( myConnections.indexOf( port ), 1 );
            break;
    }
}



回答2:


I have been neck deep in the documentation all week working around the same problem.

The problem is the MessagePort specification. The bad news being that it has no error handling, and no flag, method or event to determine whether it has been closed.

The good news is I have created a viable solution, but it's a lot of code.

Keep in mind even among the supporting browsers the activity is handled differently. For example Opera will throw an error if you attempt to message or close a closed port. The bad news is you have to use a try-catch to handle the error, the good news is you can use that feedback to close a port on at least one-side.

Chrome and Safari fail silently leaving you no feedback and no way to end invalid objects.


My solution involves delivery confirmation or a custom "callback" approach. You use a setTimeout and pass the ID for it to the SharedWorker with your command, and before processing the command it sends back a confirmation to cancel the timeout. That timeout is generally hooked to a closeConnection() method.

This takes a reactive approach instead of a pre-emptive, originally I toyed with using the TCP/IP protocol model but that involved creating more functions to handle each process.


Some Psuedo-Code as an example:

Client/Tab Code:

function customClose() {
    try {
        worker.port.close();
    } catch (err) { /* For Opera */ }
}
function send() {
    try {
        worker.port.postMessage({command: "doSomething", content: "some Data", id: setTimeout(function() { customClose(); ); }, 1000);
    } catch (err) { /* For Opera */ }
}

Thread/Worker Code:

function respond(p, d) {
    p.postMessage({ command: "confirmation", id: d.id });
}
function message(e) {// Attached to all ports onmessage
    if (e.data.id) respond(this, e.data);
    if (e.data.command) e.data.command(p, e.data);// Execute command if it exists passing context and content
}

I have placed a complete demonstration here: http://www.cdelorme.com/SharedWorker/

I am new to stack overflow, so I am not familiar with how they handle large code posts, but my full solution is two 150 line files.


Just using delivery confirmation alone is not perfect, so I have worked at improving it by adding additional components.

In particular I was investigating this for a ChatBox system, so I wanted to use EventSource (SSE), XHR, and WebSockets, only XHR is supported inside SharedWorker objects supposedly, which creates a limitation if I wanted to have the SharedWorker do all the server communication.

Plus since it needs to work for browsers without SharedWorker support I would be creating long-hand duplicate processing inside the SharedWorker which doesn't make a lot of sense.

So in the end if I implement SharedWorker it would be as a communication channel for the open tabs only, and one tab will be the Control Tab.

If the control tab is closed, the SharedWorker won't know, so I added a setInterval to the SharedWorker to send an empty response request every few seconds to all open ports. This allows Chrome and Safari to eliminate closed connections when no messages are being processed, and allows the control tab to change.

However, this also means if the SharedWorker process dies the tabs must have an interval to check in with the SharedWorker using the same approach every so often, allowing them to use the fallback approach of every-tab-for-themeselves that is inherent to all other browsers using the same code.


So, as you can see a combination of callbacks for delivery confirmation, setTimeout and setInterval must be used from both ends to maintain knowledge of connectivity. It can be done but it's a giant pain in the rear.




回答3:


PortCollection would come in handy but doesn't seem to be implemented in any browser.

It acts as an opaque array of MessagePort objects, thus allowing the objects to be garbage collected when they stop being relevant, while still allowing scripts to iterate over the MessagePort objects.

source; http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#portcollection

Edit; just rised an Issue for Chrome; http://crbug.com/263356



来源:https://stackoverflow.com/questions/13662089/javascript-how-to-know-if-a-connection-with-a-shared-worker-is-still-alive

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!