Технология SharedWorker

  Технология SharedWorker позволяет запустить асинхронное выполнение скрипта в фоновом режиме и организовать для этого скрипта интерфейсы с несколькими HTML-документами. Эти документы могут находиться в разных окнах и(или) вкладках браузера, а, также во фреймах, которые создал "родительский" документ.

  Последний вариант, пожалуй, наиболее востребованный в практике. Дело в том, что создание Web-страниц с подгружаемым контентом это оно из самых перспективных направлений развития Web-дизайна.
  Однако скрипт "родительского" документа, очевидно по соображениям безопасности, не имеет доступа к контенту "дочернего" документа.
  И в этом случае, технология SharedWorker позволяет решить эту проблему (правда в большинстве случаях это проще сделать с использованием метода postMessage, или локального хранилища).

  С помощью технологии SharedWorker можно также организовать, например, полноценную работу нескольких документов Web-страницы с SQL базой данных.
  Интерфейс SharedWorker.
  SharedWorker - Является интерфейсом к скрипту запущенному методом SharedWorker.
  Такой скрипт выполняется в фоновом режиме в своём собственном пространстве без привязки к какому-либо окну. Поэтому для этого скрипта доступен интерфейс своего пространства, которое создаёт конструктор SharedWorker.
  С помощью интерфейса SharedWorker скрипт любого документа Web-страницы может обмениваться информацией со скриптом пространства SharedWorker.
  Экземпляр доступен:

  • В выражении

      new SharedWorker(Адрес скрипта [,Имя])

    где:
    • SharedWorker - Имя функции конструктора.
    • Адрес скрипта - URL-адрес скрипта, запускаемого асинхронно (фонового скрипта), заданный в любом строковом формате.
        Этот скрипт можно создавать динамически, например, получив URL-адрес с помощью метода createObjectURL функции конструктора URL.
        Если этот скрипт ещё не запущен, то конструктор SharedWorker запускает его выполнение в фоновом режиме, параллельно с интерпретацией браузером HTML-кода любого HTML-документа.
        Если этот скрипт уже запущен из другого HTML-документа, то конструктор SharedWorker просто вернёт ссылку на интерфейс SharedWorker для этого скрипта.
    • Имя - Имя пространства скрипта, заданное в любом строковом формате.
        Один и тот же скрипт может быть параллельно запущен в разных пространствах, и, тогда, соответственно для него будут созданы разные интерфейсы SharedWorker.
  SharedWorker свойства.
  onerror - Содержит функцию, которая должна быть вызвана, если при выполнении скрипта произойдет ошибка.

Формат записи в коде скрипта:

  • Экземпляр объекта SharedWorker.onerror[ = Функция]

Значения формата записи:

  port - Содержит ссылку на интерфейс MessagePort этого SharedWorker.

Формат записи в коде скрипта:

  • Экземпляр объекта SharedWorker.port

Значения формата записи:

  workerStart - Содержит время (в секундах) от момента начала работы фонового скрипта до получения документом интерфейса SharedWorker к этому фоновому скрипту.

Формат записи в коде скрипта:

  • Экземпляр объекта SharedWorker.workerStart

Значения формата записи:

  SharedWorker методы.
  addEventListener - Устанавливает функцию обработчик событий, связанных с пространством выполняющегося скрипта.
  Возвращает значение undefined.

Формат записи в коде скрипта:

  • Экземпляр объекта SharedWorker.addEventListener(Событие, Функция, false)

Значения формата записи:

  • Экземпляр объекта SharedWorker - Любой операнд значения со значением экземпляра объекта SharedWorker.
  • . - Оператор доступа к методу объекта.
  • addEventListener - Ключевое слово.
  • ( - Оператор группировки. Ключевое слово в этом формате.
  • Событие - Имя события, предусмотренного для объекта SharedWorker, заданное в любом строковом формате (только "error").
  • Функция - Любой операнд значения со значением функция.
      Значением первого аргумента этой функции, при ее вызове браузером, всегда является экземпляр объекта Event обрабатываемого события.
      Одна функция-обработчик устанавливается методом addEventListener только один раз, и повторные вызовы метода для этой же функции не имеют значения.
      Однако другие функции могут быть установлены экземпляру объекта SharedWorker методом addEventListener для этого же события, причем выполняться, в случае возникновения события, они будут в том же порядке, как записаны в скрипте.
  • false - Логическое значение.
  • , - Оператор группировки. Ключевое слово в этом формате.
  • ) - Оператор группировки. Ключевое слово в этом формате.
  dispatchEvent - Инициализирует возникновение заданного события в пространстве выполняющегося скрипта.
  Возвращает значение undefined.
  Инициализированное событие не происходит на самом деле, но инициализация приводит к вызову его обработчика.

Формат записи в коде скрипта:

  • Экземпляр объекта SharedWorker.dispatchEvent(Событие)

Значения формата записи:

  removeEventListener - Отменяет функцию обработчик событий установленную методом addEventListener.
  Возвращает значение undefined.

Формат записи в коде скрипта:

  • Экземпляр объекта SharedWorker.removeEventListener(Событие, Функция, false)

Значения формата записи:

  Интерфейс MessagePort.
  MessagePort - Является интерфейсом к порту обмена информацией со скриптом запущенным методом SharedWorker.
  Каждый документ - создавший интерфейс SharedWorker получает порт обмена информацией с соответствующим скриптом, работающим в фоновом режиме.
  Этот порт симметричный, двухсторонний, одной стороной является документ, другой стороной - фоновый скрипт.
  Соответствующий экземпляр объекта MessagePort и поддерживает интерфейс к такому порту с каждой стороны.
  Интерфейс к порту, который получил документ, становится доступен фоновому скрипту при подключении к этому порту этого документа.
  Экземпляр доступен:

  MessagePort свойства.
  onmessage - Содержит функцию, которая должна быть вызвана, если получено сообщение в этот порт.
  Функция обработчик события message может быть назначена документом (скриптом документа) и фоновым скриптом.
  Соответственно одна из них будет обрабатывать в документе сообщения от пространства фонового скрипта, а другая в фоновом скрипте от документа.

Формат записи в коде скрипта:

  • Экземпляр объекта MessagePort.onmessage[ = Функция]

Значения формата записи:

  • Экземпляр объекта MessagePort - Любой операнд значения со значением экземпляра объекта MessagePort.
  • . - Оператор доступа к свойству объекта.
  • onmessage - Ключевое слово.
  • = - Оператор присвоения. Ключевое слово в этом формате.
  • Функция - Любой операнд значения со значением функция.
      Значением первого аргумента этой функции, при ее вызове браузером, всегда является экземпляр объекта Event обрабатываемого события.
      Если свойством onmessage назначена функция обработчик, то произойдёт автоматическое подключение соответствующего субъекта обмена (документа или фонового скрипта) к этому порту.
      Если к порту подключается документ, то в пространстве фонового скрипта возникнет событие connect.
  MessagePort методы.
  addEventListener - Устанавливает функцию обработчик событий для этого порта.
  Возвращает значение undefined.
  По существу в порту может возникнуть только одно событие - message.
  Функция обработчик события message может быть назначена документом и фоновым скриптом.
  Соответственно одна из них будет обрабатывать в документе сообщения от скрипта, а другая в скрипте от документа.

Формат записи в коде скрипта:

  • Экземпляр объекта MessagePort.addEventListener(Событие, Функция, false)

Значения формата записи:

  • Экземпляр объекта MessagePort - Любой операнд значения со значением экземпляра объекта MessagePort.
  • . - Оператор доступа к методу объекта.
  • addEventListener - Ключевое слово.
  • ( - Оператор группировки. Ключевое слово в этом формате.
  • Событие - Имя события, предусмотренного для объекта MessagePort, заданное в любом строковом формате (только "message").
  • Функция - Любой операнд значения со значением функция.
      Значением первого аргумента этой функции, при ее вызове браузером, всегда является экземпляр объекта Event обрабатываемого события.
      Одна функция-обработчик устанавливается методом addEventListener только один раз и повторные вызовы метода для этой же функции не имеют значения.
      Однако другие функции могут быть установлены экземпляру объекта MessagePort методом addEventListener для этого же события, причем выполняться, в случае возникновения события, они будут в том же порядке, как записаны в скрипте.
  • false - Логическое значение.
  • , - Оператор группировки. Ключевое слово в этом формате.
  • ) - Оператор группировки. Ключевое слово в этом формате.
  close - Разрывает подключение к этому порту.
  Возвращает значение undefined.
  Подключение может быть разорвано для того, чтобы заменить функцию обработчик.
  Подключение лучше разрывать при окончании работы соответствующего документа.

Формат записи в коде скрипта:

  • Экземпляр объекта MessagePort.close()

Значения формата записи:

  dispatchEvent - Инициализирует возникновение заданного события в этом порту.
  Возвращает значение undefined.
  Инициализированное событие не происходит на самом деле, но инициализация приводит к вызову его обработчика.
  Инициализация события message может быть выполнена документом и фоновым скриптом.
  Соответственно это событие будет обработано в документе или в фоновом скрипте.

Формат записи в коде скрипта:

  • Экземпляр объекта MessagePort.dispatchEvent(Событие)

Значения формата записи:

  postMessage - Передает сообщение в этот порт.
  Возвращает значение undefined.
  Соответственно у контрагента в этом порту возникнет событие message.

Формат записи в коде скрипта:

  • Экземпляр объекта MessagePort.postMessage(Сообщение)

Значения формата записи:

  • Экземпляр объекта Self - Любой операнд значения со значением экземпляра объекта Self.
  • . - Оператор доступа к методу объекта.
  • postMessage - Ключевое слово.
  • ( - Оператор группировки. Ключевое слово в этом формате.
  • Сообщение - Любой формат данных JavaScript.
      Сообщение будет доступно контрагенту в свойстве data события message.
      В порт передаётся не ссылка на данные, а их копия, созданная с преобразованием в формат JSON (при получении из порта преобразуются обратно).
      Соответственно у браузеров есть ограничения на передачу не примитивных объектов.
  • ) - Оператор группировки. Ключевое слово в этом формате.
  removeEventListener - Отменяет функцию обработчик событий установленную методом addEventListener.
  Возвращает значение undefined.

Формат записи в коде скрипта:

  • Экземпляр объекта MessagePort.removeEventListener(Событие, Функция, false)

Значения формата записи:

  start - Устанавливает подключение к этому порту.
  Возвращает значение undefined.
  Подключение должно быть установлено сначала документом (скриптом документа), а затем уже фоновым скриптом.
  Соответственно метод start, вызванный в документе, инициирует событие connect в пространстве фонового скрипта.
  Функция обработчик для этого события, установленная в фоновом скрипте, должна выполнить подключение к этому порту со стороны фонового скрипта.
  Метод start применяется только после метода addEventListener.
  Если обработчик события message устанавливается свойством onmessage, то подключение соответствующего участника обмена (документа или фонового скрипта) к этому порту происходит автоматически.
  Подключение может быть разорвано методом close.

Формат записи в коде скрипта:

  • Экземпляр объекта MessagePort.start()

Значения формата записи:


  Алгоритм подключения к фоновому скрипту в технологии SharedWorker довольно замысловат, поэтому требует отдельного пояснения:
  1. Документ (скрипт документа) должен получить интерфейс SharedWorker.
      При этом, если фоновый скрипт не был запущен в указанном пространстве, то он будет запущен.
      В любом случае документу станет доступным - порт для обмена данными с фоновым скриптом.
  2. Фоновый скрипт должен установить обработчик события connect.
  3. Документ должен установить подключение к доступному - порту.
      Подключение устанавливается либо заданием значения свойству onmessage, либо последовательным вызовом методов addEventListener и start.
      В любом случае для документа будет установлен обработчик события, связанного с получением данных в этом порту от фонового скрипта, а в пространстве фонового скрипта возникнет событие connect.
  4. Обработчик события connect фонового скрипта должен установить подключение к переданному ему порту, к которому подключился документ.
      Интерфейс порта передаётся в первом элементе массива ports (ports[0]).
      Подключение устанавливается либо заданием значения свойству onmessage, либо последовательным вызовом методов addEventListener и start.
      В любом случае для фонового скрипта будет установлен обработчик события, связанного с получением данных в этом порту от документа.
  5. Фоновый скрипт должен подтвердить подключение к порту со своей стороны.
  Для отладки фоновых скриптов большинство браузеров предоставляют отдельный сервис (например - chrome://inspect/#workers), который включает и окно консоли.

Пример.

        "Родительский" документ:
<IFRAME ID="YYY" NAME="ZET" width="250px" height="60px" ></IFRAME>
<BR>
<BUTTON ID="STARTW" >Подключиться к SharedWorker</BUTTON>
<BUTTON ID="ENDW" DISABLED>Отключиться от SharedWorker</BUTTON><BR><BR>
<TEXTAREA ID="POSTW" PLACEHOLDER="Введите сообщение" ></TEXTAREA>
    <BUTTON ID="SENDW" DISABLED>Отправить сообщение</BUTTON><BR><BR>
<DIV ID="TOW">Журнал SharedWorker:</DIV>
<SCRIPT>
  var worker = null;
  var sen = null;
  var st = [0,0,0,0];
  var pt = null;
  var FRM = document.getElementById("YYY");
  var STARTW = document.getElementById("STARTW");
  var POSTW = document.getElementById("POSTW");
  var SENDW = document.getElementById("SENDW");
  var ENDW = document.getElementById("ENDW");
  var TOW = document.getElementById("TOW");
  var res = function(e)
   {
     sen = TOW.innerHTML + "<BR>" + e.data[1];
     TOW.innerHTML = sen;
     TOW.scrollBy(0,25);
     if (st[0] == 1)
      {
        ENDW.disabled = false;
        STARTW.disabled = true;
        FRM.src = "../content/testSW.htm";
        st[0] = 0;
        st[1] = e.data[0];
      }
     if (e.data[0] == 1)
      {
        SENDW.disabled = false;
      }
     if (st[0] == 2)
      {
        SENDW.disabled = true;
        ENDW.disabled = true;
        STARTW.disabled = false;
        FRM.src = "";
      }
   };
  var start = function ()
   {
     worker = new SharedWorker("../script/SWorker.js","doc1" );
     pt = worker.port;
     st[0] = 1;
     pt.addEventListener("message", res, false);
     pt.start();
   };
  var stop = function ()
   {
     st[0] = 2;
     pt.postMessage(st);
   };
  var send = function ()
   {
     st[0] = 0;
     st[2] = POSTW.value;
     st[3] = 1;
     pt.postMessage(st);
   };
  STARTW.onclick = start;
  SENDW.onclick = send;
  ENDW.onclick = stop;

</SCRIPT>
     "Дочерний" документ:
<DIV ID=XXX>
  Рыба
</DIV>
<SCRIPT>
  var worker = null;
  var sen = null;
  var st = [0,0,0,0];
  var pt = null;
  var FRM = document.getElementById("XXX");
  var res = function(e)
   {
     FRM.innerText = e.data;
   };
  worker = new SharedWorker("../script/SWorker.js","doc1" );
  pt = worker.port;
  st[0] = 1;
  pt.addEventListener("message", res, false);
  pt.start();

</SCRIPT>

     SWorker.js:
 var D = null;
 var port = null;
 var mes = null;
 var L = null;
 var J = null;
 var ports = [];
 var sen = [null,null];
 var mess = function (e)
 {
  D = new Date();
  var data = e.data;
  switch (data[0])
   {
     case 0:
      sen[1] = "<I>" + D.toLocaleString() + "</I>" + " SWorker <I>получено от <EM> "
        + data[1] + "</EM></I> - <KBD>«" + data[2] + "»</KBD>
        <I>для</I> <EM>" + data[3] + "</EM>";
      ports[0].postMessage(sen);
      if (data[3] == 1)
       {
         sen[1] = "<I>" + D.toLocaleString() + "</I>"
           + " SWorker <I>отправлено от <EM>" +
           data[1] + "</EM></I> - «<KBD>"
           + data[2] + "</KBD>» <I>в</I> <EM> " + data[3] + "</EM>";
         ports[0].postMessage(sen);
         ports[1].postMessage(data[2]);
       }
      break;
     case 2:
      L = ports.length;
      for (J = L - 1; J > -1; J--)
       {
         sen[1] = "<I>" + D.toLocaleString() + "</I>" +
         " SWorker <I>отключение, порт</I><KBD>" + " - " + J + "</KBD>";
         ports[0].postMessage(sen);
         ports[J].close();
       }
      D = null;
      port = null;
      mes = null;
      L = null;
      J = null;
      ports = [];
      sen = [null,null];
      break;
   };
 };
 var conn = function (e)
 {
   port = e.ports[0];
   port.addEventListener("message", mess , false);
   L = ports.length;
   ports[L] = port;
   sen[0] = L;
  port.start();
   D = new Date();
   sen[1] = "<I>" + D.toLocaleString() + "</I>"
     + " SWorker <I>подключение, порт" + " - <EM>" + L + "</EM></I>";
  ports[0].postMessage(sen);
 }
 addEventListener("connect", conn , false);

Результат.



    

Журнал SharedWorker: