Подтвердить что ты не робот

JavaScript: как узнать, жива ли связь с общим работником?

Я пытаюсь использовать общий рабочий для ведения списка всех окон/вкладок веб-приложения. Поэтому используется следующий код:

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

Каждый раз, когда создается окно, соединение устанавливается с рабочим работником shared-worker.js, и рабочий добавляет соединение с окном в список connections.

Когда пользователь закрывает окно, его соединение с общим рабочим истекает и должно быть удалено из переменной connections. Но я не нахожу надежного способа сделать это.

Глядя на спецификацию, объекты переменной connections, похоже, не содержат свойство/функцию, чтобы проверить, жив ли соединение.

Возможно ли это?
Опять же, общая цель состоит в том, чтобы иметь список всех окон/вкладок.

РЕДАКТИРОВАТЬ:. Подход будет состоять в том, чтобы сделать совместное сообщение с рабочим пользователем и ожидать ответа. Если общий пользователь не получает ответа, он предполагает, что окно закрыто. В моих экспериментах этот подход не доказал свою надежность; проблема заключается в том, что невозможно определить, закрыто ли окно или просто требуется много времени для ответа.

4b9b3361

Ответ 1

Это так же надежно, как и перед загрузкой, но, похоже, работает (протестировано в Firefox и Chrome). Я определенно одобряю это решение опроса.

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

Затем обработайте очистку объекта порта в 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

В течение всей недели я работал с шеей в документации, связанной с той же проблемой.

Проблема заключается в спецификации MessagePort. Плохая новость заключается в том, что у него нет обработки ошибок, а не флажок, метод или событие, чтобы определить, было ли оно закрыто.

Хорошей новостью является то, что я создал жизнеспособное решение, но он много кода.

Помните, что даже среди поддерживающих браузеров активность обрабатывается по-разному. Например, Opera будет вызывать ошибку, если вы попытаетесь отправить сообщение или закрыть закрытый порт. Плохая новость заключается в том, что вы должны использовать try-catch для обработки ошибки, хорошая новость заключается в том, что вы можете использовать эту обратную связь, чтобы закрыть порт по крайней мере на одной стороне.

Chrome и Safari не дают вам никакой обратной связи и не могут завершить недопустимые объекты.


Мое решение включает подтверждение доставки или пользовательский подход "обратного вызова". Вы используете setTimeout и передаете идентификатор для него в SharedWorker с помощью своей команды, а перед обработкой команды он отправляет подтверждение для отмены таймаута. Этот тайм-аут обычно подключается к методу closeConnection().

Это требует реактивного подхода вместо упреждающего, изначально я играл с использованием модели протокола TCP/IP, но это включало создание дополнительных функций для обработки каждого процесса.


В качестве примера можно привести несколько Псевдо-код:

Код клиента/вкладки:

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 */ }
}

Тема/Рабочий код:

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
}

Я разместил здесь полную демонстрацию: http://www.cdelorme.com/SharedWorker/

Я новичок в переполнении стека, поэтому я не знаком с тем, как они обрабатывают большие кодовые сообщения, но мое полное решение - это два 150 файла строк.


Просто использование подтверждения доставки не является совершенным, поэтому я улучшил его, добавив дополнительные компоненты.

В частности, я изучал это для системы ChatBox, поэтому я хотел использовать EventSource (SSE), XHR и WebSockets, только XHR поддерживается внутри объектов SharedWorker якобы, что создает ограничение, если я хочу, чтобы SharedWorker делал все сообщения сервера.

Плюс, так как он должен работать для браузеров без поддержки SharedWorker, я бы создавал длинную ручную дублирующую обработку внутри SharedWorker, которая не имеет большого смысла.

Итак, в конце, если я реализую SharedWorker, он будет как канал связи только для открытых вкладок, а одной вкладкой будет вкладка "Управление".

Если вкладка управления закрыта, SharedWorker не будет знать, поэтому я добавил setInterval в SharedWorker, чтобы отправлять пустой запрос ответа каждые несколько секунд всем открытым портам. Это позволяет Chrome и Safari устранять закрытые соединения, когда никакие сообщения не обрабатываются, и позволяет изменять вкладку управления.

Однако это также означает, что если процесс SharedWorker умирает, вкладки должны иметь интервал для проверки с помощью SharedWorker с использованием одного и того же подхода так часто, что позволяет им использовать резервный подход для каждой вкладки для темы, присущий всем другим браузерам, использующим тот же код.


Итак, поскольку вы можете видеть комбинацию обратных вызовов для подтверждения доставки, setTimeout и setInterval должны использоваться с обоих концов, чтобы поддерживать знание возможности подключения. Это можно сделать, но это гигантская боль в тылу.

Ответ 3

PortCollection пригодится, но, похоже, не реализован ни в одном браузере.

Он действует как непрозрачный массив объектов MessagePort, тем самым позволяя собирать мусор, когда они перестают быть релевантными, но все же позволяет сценариям перебирать объекты MessagePort.

источник; http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#portcollection

Изменить; только что поднял проблему для Chrome; http://crbug.com/263356