В JavaScript есть основной поток, в котором выполняется весь код. Для параллельного выполнения кода в отдельных потоках в JavaScript появились веб-воркеры.
- Основной потом и воркеры полностью изолированы и не имеют доступа к переменным друг друга. Это позволяет избегать конфликтов параллельного доступа к общим ресурсам, как, например, race condition.
- Воркеры не имеют доступа к DOM — не получится использовать воркер для обновления UI, он может только обработать большой объем данных.
- Главный потом и воркеры общаются между собой с помощью сообщений.
Есть три типа воркеров:
- dedicated
- shared
- service
Пример:
// в главном потоке
const worker = new Worker('./generate.js')
worker.postMessage({
command: 'generate',
quota: quota
})
worker.addEventListener('message', message => {
console.log(message)
})
// в воркере
addEventListener('message', message => {
console.log(message.data)
})
postMessage('Hi!')
postMessage({
result: 123,
})
Сигнатура postMessage
:
postMessage(message, targetOrigin)
postMessage(message, targetOrigin, [transfer])
Shared-воркеры отличаются от обычных тем, что к ним могут обращаться сразу несколько документов.
С их помощью можно организовать коммуникацию между несколькими окнами.
const worker = new SharedWorker('worker.js')
У shared-воркера есть свойство port
, которое представляет собой инстанс объекта MessagePort
:
worker.port.start()
worker.port.postMessage([first.value,second.value])
myWorker.port.onmessage = function(e) {
console.log(e.data)
}
Внутри воркера:
onconnect = function(e) {
var port = e.ports[0];
port.addEventListener('message', function(e) {
var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
port.postMessage(workerResult);
});
port.start(); // Required when using addEventListener. Otherwise called implicitly by onmessage setter.
}
Сервис-воркеры позволяют перехватывать запросы к серверу и обрабатывать их. Таким образом, например, можно организовать кеширование данных на уровне сервис-воркера.
Также из сервис-воркеров можно отправлять пуш-уведомления.
Сначала необходимо зарегистрировать сервис-воркер с помощью метода register
объекта navigator.serviceWorker
:
if ('serviceWorker' in navigator) {
// Supported!
navigator.serviceWorker.register('/sw.js', options)
.then(function(serviceWorkerRegistration)
}
При регистрации указывается путь у файлу с сервис-воркером и возвращается промис.
Жизненный цикл сервис-воркера:
В случае успешной установки, в сервис-воркере срабатывает событие install
:
self.addEventListener('install', event => {
//
})
Также у сервис воркера есть события activate
, idle
, fetch
.
self.addEventListener('fetch', event => {
// в метод respond with можно передать значение или промис
event.respondWith(...)
})
У серсис-воркеров есть API для кеширования - CacheStorage
, которое доступно под названием caches
.
- Cache only
- Network only
- Cache falling back to network
- Network falling back to cache
- Generic fallback