Если вы использовали Javascript, вы, возможно, знаете, что это однопоточный язык сценариев, который работает в файлах HTML. Это означает, что одновременно выполняется только один оператор.

Однако мы также знаем, что JS имеет асинхронное поведение, с помощью которого мы можем добиться параллелизма. Но Асинхронность не является многопоточной, так как она также зависит от одного потока. В какой-то степени даже асинхронные операции блокируют рендеринг DOM в браузере.

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

Итак, как добиться многопоточности в JS?
Ответ — Web Workers! В JavaScript вы можете использовать параллельное программирование для одновременного выполнения нескольких операций с помощью веб-воркеров.

Один из способов думать о веб-воркерах — это фрагменты кода, которые представляют собой ресурсоемкие задачи, выполнение которых занимает много времени. Мы передаем эту дорогостоящую логику браузеру для выполнения в фоновом режиме (отдельный поток). Поскольку он работает в фоновом режиме, он не влияет на JavaScript в основном потоке, отвечающем за веб-страницу.

Веб-воркеры — это код JavaScript, который выполняется в отдельном потоке без прямого доступа к DOM.

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

Как использовать веб-воркеров в JavaScript

Для создания нового рабочего процесса мы используем конструктор Worker(), указав URI скрипта для выполнения в рабочем потоке в файле main.js.

Рабочий код должен находиться в отдельном файле, в данном случае worker.js, который мы можем использовать для создания отдельного рабочего потока с помощью конструктора Worker и передачи его пути к файлу. .

// main.js
if (window.Worker) {
   const myWorker = new Worker('worker.js');
} else {
   console.log('Your browser doesn't support web workers');
}

Отправка и получение сообщений от выделенного работника может быть достигнуто с помощью метода postMessage() и обработчика событий onmessage. Тип данных сообщения может быть строкой, числом, логическим значением, массивом, объектом, нулевым значением или неопределенным. Данные всегда передаются по значению и сериализуются, а затем десериализуются в процессе связи.

Вы можете передать только один аргумент в postMessage. Если вы хотите передать несколько аргументов, используйте вместо них object.

// main.js
// To receive the message from worker
myWorker.onmessage = (event) => {
  var message = event.data;
  ...
};
OR
myWorker.addEventListener('message', function(event) {
  var message = event.data;
  ...
});
--------
// To post a message to worker
myWorker.postMessage('Posting a new message'); 

Теперь, чтобы рабочий процесс услышал сообщение, нам нужно установить прослушиватель событий в файле worker.js для события сообщения.

// worker.js
// To receive message from main thread
self.addEventListener('message', function(event) {
// message received from main thread
  var message = event.data;
  ...
// To post a message to main thread
  self.postMessage("message received");
});
OR
self.onmessage = (event) => {
  var message = event.data;
  ...
// To post a message to main thread
  self.postMessage("message received");
 };

Любые логические ошибки, вызванные данными, переданными сценарием, могут быть обнаружены с помощью обработчика событий onerror.

// main.js
myWorker.onerror = function(event) {
  console.log("Error in file: "+event.filename+");
  console.log("Error in Line number: "+event.lineno+");
  console.log("Error Description: "+event.message+");
};

Рабочий веб-поток можно остановить с помощью метода close().

// worker.js
self.addEventListener('message', function(event) {
  var message = event.data;
  self.postMessage('message received');
  self.close();                // Closing the thread
});

Пункты, которые следует отметить

  1. Данные, которыми обмениваются основной поток и рабочие потоки, копируются, а не совместно используются.
  2. Вы не можете обновлять DOM из рабочего потока, поскольку они выполняются в отдельном контексте от главного окна.
  3. Рабочие не имеют доступа к объектам window и document, но у них есть доступ к некоторым возможностям объекта window, таким как Websockets и indexedDB.. Кроме того, он может получить доступ к Location, AppCache.
  4. Сценарий должен обслуживаться с того же хоста или домена из соображений безопасности, и по этой же причине веб-воркеры не будут работать, если мы откроем файл локально по схеме file://.

Варианты использования веб-воркеров

Любые интенсивные вычисления ЦП, которые блокируют основной поток пользовательского интерфейса, могут быть выгружены на Web Worker. Вот несколько вариантов использования рабочих:

  1. Предварительная выборка и/или кэширование.
  2. Веб-ввод/вывод — опрос URL-адресов в фоновом режиме. Таким образом, вы не блокируете пользовательский интерфейс в ожидании результатов опроса.
  3. Обработка больших наборов данных или Обновление строк локальной веб-базы данных (indexedDB).
  4. Рисование на холсте, фильтрация изображений и манипулирование изображениями.
  5. Подсветка синтаксиса кода или форматирование текста в реальном времени.

Заключение

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