Веб-воркеры позволяют нам использовать многопоточность в браузере с помощью Javascript. Есть много простых примеров того, как это сделать, но я собираюсь показать способ сделать ваших воркеров очень расширяемыми с помощью общего интерфейса в Vue3! Эти же концепции легко применимы к Angular, React или любому фреймворку Javascript.

Весь код, из которого я буду брать примеры, можно разветвить/скачать по ссылке ниже. Если вы считаете, что у вас есть хорошая идея, не стесняйтесь следовать за ней или даже вносить коммит!



Для начала давайте сначала поговорим о том, что такое Web Worker. Javascript — это однопоточный язык, что означает, что любое выполнение, выполняемое в стеке, должно завершиться перед переходом к следующему элементу.

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

Создать веб-воркер довольно просто. Вы создаете рабочий файл, который соответствует рабочему интерфейсу, используя свойство onmessage:

Worker.js
###

onmessage = function(e) {
  var results = e.data + 1;
// Post message back to whoever implemented the worker.
  postMessage(result);
}

Затем вы реализуете воркера, создав экземпляр нового воркера с путем к вашему воркеру:

App.vue
###

var worker = new Worker("PATH_TO_YOUR_WORKER_DIR/Worker.js");
// send message to worker
worker.postMessage(1);
// receive messages back from worker when it needs to communicate back
worker.onmessage = function(event) {
  // get data from worker's message 
  var updatedValueFromWorker = event.data;
}

Рабочий процесс и все, что его реализует, взаимодействуют друг с другом через интерфейсы postMessage и onmessage.

Приведенному выше примеру очень легко следовать и быстро настроить, но он может ограничивать возможности вашего воркера. Если весь ваш код находится в собственности onmessage вашего работника, это может очень быстро привести к тому, что огромный объем кода будет неправильно разделен и будет трудно читать.

Для меня более удобоваримый подход состоял в том, чтобы относиться к рабочим файлам как к классу, который несет одну единственную ответственность и придерживается интерфейса, который требует, чтобы он имел свойство onmessage для внешней связи. Давайте возьмем пример из репозитория Github, который я связал:

Здесь у нас есть рабочий файл, который считает разные числа (да, есть более простые способы сделать это, но для примера отложим недоверие).

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

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

Реализовать этого воркера очень просто:

Как и в предыдущем примере, я создаю новый экземпляр Worker с путем к моему файлу countWorker.js. Я создаю обработчик onmessage, чтобы обработчик мог связаться со мной, а затем я вызываю worker.postMessage, но на этот раз я указываю, что я хочу, чтобы обработчик делал для меня, передав { type: 'countToOneHundredThousand' }в данных сообщения.

Если вы хотите увидеть фактические результаты рабочего процесса, откройте репозиторий и посмотрите на разницу между нажатием кнопки Однопоточное выполнение и кнопки Многопоточное выполнение. . Вы заметите, что время выполнения основного потока кнопки Multi Threaded Execution практически ничего не значит!