Web Workers API

Web Workers API служит для запуска скриптов в фоне. Если нам необходимо запустить в фоне какие-либо вычисления, да еще и в несколько потоков, то это подходящий инструмент для таких целей. Так как работа происходит в фоне, то при этих вычислениях рендеринг страницы не блокируется. Все происходит параллельно.

Доступность в браузерах по данным CanIUse

С создавшим его кодом каждый Web Worker общаеся через отправку событий.

Есть разные типы вокеров. Простейшим является выделенный воркер.

Создание и взаимодействие

Создание выделенного воркера происходит просто:

if (window.Worker) {
    // Создание воркера
    var myWorker = new Worker("worker.js");
    // Обработчик событий (получение данных) от воркера
    myWorker.onmessage = function(e) {
        console.log("Message received from worker", e.data);
    }
    // Отправка данных воркеру
    myWorker.postMessage([34, 10]);
}

Здесь проверяется доступность Web Wokres API и создается воркер из файла worker.js, а также добавляется обработка событий от воркера.

Код worker.js может содержать функцию onmessage для приема данных от основного js кода:

onmessage = function(e) {
  // Получение данных от основного кода
  console.log("Message received from main script", e.data);
  var workerResult = e.data[0]*e.data[1];
  console.log("Posting message back to main script");
  // Отправка результата в основной код
  postMessage(workerResult);
}

Если первый код вставить в index.html между тегами script, а второй кусок кода поместить в wokrer.js, то запустив index.html мы получим в консоли браузера сообщения:

Message received from main script (2) [34, 10]
Posting message back to main script
Message received from worker 340

У MDN есть пример simple-web-worker. И demo. Там код лишь немного сложнее. Показаны 2 воркера.

Worker-ы могут запускать другие worker-ы. Главное чтобы политика одного источника (в браузере) соблюдалась.

Также из воркеров имеется доступ к функции importScripts("foo.js", "bar.js" ...); для загрузки скриптов извне. Загрузка должна быть только с того же домена.

Ограничения

В воркере нельзя обращаться к DOM. Нет доступа к localStorage. Эти вещи можно делать только передав событие основному коду, который сделает все что нужно.

Разделяемые воркеры

Разделяемый воркер доступен нескольким разным скриптам — даже если они находятся в разных окнах, фреймах или даже воркерах.

Создается такой воркер похожим образом:

var myWorker = new SharedWorker("worker.js");

Как видно, в данном случае используется конструктор SharedWorker.

С разделяемым worker-ом необходимо взаимодействовать через объект port — явно открыв порт, с помощью которого скрипты могут взаимодействовать с worker-ом. Для выделенного worker-а это происходит тоже, но неявно (через onmessage).

Соединение с портом должно быть осуществлено либо неявно, используя обработчик событие onmessage, либо явно, вызвав метод start() перед тем, как отправлять любые сообщения.

Например, в родительском потоке можно

// Открываем порт
myWorker.port.start();
// Передаем данные
myWorker.port.postMessage(["value1", "value2", "value3"]);

При этом на стороне воркера:

// Необходим addEventListener() для события onconnect
self.addEventListener("connect", function(e) {
  var port = e.ports[0]; // Получаем первый порт
  port.onmessage = function(e) {
    var workerResult = "Result: " + (e.data[0] + e.data[1] + e.data[2]);
    port.postMessage(workerResult);
  }
});

В родительском потоке:

myWorker.port.onmessage = function(e) {
  console.log("Message received from worker", e.data[0]);
}

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

Передача данных в воркеры и из них

Данные в воркеры и из них передаются копированием при помощи сериализации. По ссылке данные не передаются. Однако у Chrome 17+ и Firefox 18+ имеется возможность передать некоторые типы объектов по ссылке. Это объекты, которые реализуют интерфейс Transferable. Пока что это только ArrayBuffer и MessagePort.

Чтобы передать таким образом параметр необходимо воспользоваться вторым аргуметом метода postMessage:

var ab = new ArrayBuffer(size);
worker.postMessage({ data: ab }, [ab]);

Другие типы воркеров

Имеются развноидности воркеров.

  • ServiceWorkers — служат для реализации работы приложений в условиях потери связи. С помощью них можно реализовать выдачу закешированного результата. А также push-уведомления, и фоновую синхронизацию. caniuse
  • Chrome Workers — это воркеры которые используются при разработке расширений к браузеру Firefox.
  • Audio Workers для работы с audio потоком из воркеров. Но не реализованы пока в браузерах
  • Встроенные воркеры

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *