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 потоком из воркеров. Но не реализованы пока в браузерах
- Встроенные воркеры