JavaScript - это однопоточный язык, что означает, что он выполняет код по порядку и должен завершить выполнение фрагмента кода, прежде чем перейти к следующему.

Для HTTP-запросов JavaScript предоставляет нам XMLHttpRequest, который не является блокирующим, но если у нас есть код, интенсивно использующий процессор, он будет блокировать основной поток до тех пор, пока он не будет выполнен, в результате чего пользовательский интерфейс не будет отвечать в течение этого периода. Один из способов решения этой проблемы - использовать setTimeout или setInterval. Мы можем разбить код, интенсивно использующий процессор, на более мелкие части и привязать к нему тайм-аут. Хотя это может работать для небольших программ, по мере увеличения сложности кода становится трудно решить, где добавить функции тайм-аута. Нам нужен отдельный поток, в котором выполняются эти вычисления, что делает основной поток свободным для обработки событий пользовательского интерфейса, манипулирования DOM или выполнения других задач.

Веб-воркеры спешат на помощь

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

Типы веб-воркеров

Создавая отдельные потоки для параллельной программы JavaScript, Worker thread позволяет добиться многопоточности. Есть два типа веб-воркеров.

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

Общие воркеры: общие воркеры могут быть доступны всем процессам, работающим в одном и том же источнике (разные окна, вкладки браузера, окна iframe или другие общие воркеры).

В этой статье рассматриваются только преданные своему делу сотрудники, и я буду называть их «веб работниками» или «работниками».

Начиная

Веб-воркеры работают в изолированном потоке в браузере. Следовательно, код, который они выполняют, содержится в отдельном файле JavaScript и включается в вашу страницу с помощью асинхронных HTTP-запросов. Для создания рабочего потока мы добавляем следующие строки на нашу главную страницу.

var worker = new Worker(‘calculate.js’);

Если файл «calculate.js» существует и доступен, браузер создаст новый поток, который загружает файл асинхронно. Сразу после завершения загрузки она будет выполнена, и начнется рабочий процесс. Если предоставленный путь к файлу возвращает 404, рабочий завершит работу без предупреждения.

Чтобы запустить воркер, мы должны вызвать метод postMessage ().

worker.postMessage(message, [transfer]);

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

Связь между веб-исполнителем и главной страницей осуществляется двумя способами: методом postMessage () и обработчиком события «message».

postMessage может принимать в качестве единственного аргумента строку или объект JSON. Новые браузеры поддерживают объект JSON в качестве первого параметра метода, тогда как старые браузеры поддерживают только строку. Когда сообщение отправляется из postMessage (), другая страница получит событие как событие «сообщение». Для обработки ошибок передается событие «error».

В приведенном выше примере main.html вызывает двух рабочих процессов (простое и факториальное) с помощью postMessage. Я использовал отдельные веб-воркеры для простых методов и методов Фибоначчи, оба метода символизируют большие вычисления.

primeWorker.postMessage({cmd:'first50'});
 
fibonacciWorker.postMessage({cmd:'first100'});

Рабочие файлы сами прослушивают событие 'message', и как только они получают событие, они производят свои вычисления и отправляют результат обратно с помощью self.postMessage метод. Я также добавил третью кнопку для изменения цвета фона, она символизирует изменения пользовательского интерфейса. Когда вы вызываете prime или factorial из скрипта, создается независимый параллельный рабочий поток Web, который будет работать с этими методами, и параллельно вы можете вносить изменения в пользовательский интерфейс, нажав кнопку изменения фона.

В файл main.html я также добавил прослушиватель событий error.

fibonacciWorker.addEventListener('error', errorEvent, false);

если ошибка возникает во время выполнения рабочего, запускается ErrorEvent. Этот интерфейс содержит три полезных свойства для определения того, что пошло не так: filename - имя рабочего скрипта, вызвавшего ошибку, lneno - номер строки, в которой произошла ошибка, и сообщение - содержательное описание ошибки.

Вы, должно быть, заметили, что я использовал «self» в prime.js и « this» в fibonacci.js, потому что в контексте рабочий, оба типа «я» и «это» ссылаются на глобальную область видимости для рабочего.

Здесь, если бы мы не использовали веб-воркеров, браузер завис бы на время вычислений функций Фибоначчи и простых чисел, и вы не смогли бы взаимодействовать с пользовательским интерфейсом в это время.

Импорт скриптов и библиотек

Рабочие потоки могут импортировать внешний скрипт с помощью метода importScripts (). Он принимает ноль или более URI в качестве параметров импортируемых ресурсов. Браузер загружает каждый указанный скрипт и выполняет его. Затем рабочий может использовать любые глобальные объекты из каждого сценария. Если скрипт не может быть загружен, выдается NETWORK_ERROR, и последующий код выполняться не будет.

importScripts(‘foo.js’); /* imports just “foo.js” */
importScripts(‘foo.js’, ‘bar.js’);
importScripts('//example.com/hello.js'); 

Подработники

Рабочие могут создавать больше потоков подработников. Это отлично подходит для дальнейшего разделения больших задач во время выполнения. Однако у подработников есть свои условия:

⦁ Подработники должны размещаться в том же источнике, что и родительская страница.

⦁ URI внутри подчиненных разрешаются относительно местоположения их родительского работника. Это упрощает работникам отслеживание их зависимостей.

Но при создании подчиненных мы должны быть осторожны, чтобы не перегружать системные ресурсы пользователя.

Встроенные рабочие

Если вы хотите создать рабочий скрипт на лету или не хотите создавать отдельные файлы для рабочих. Вы можете встроить все это на одну страницу с помощью Blob и блоков данных.

С помощью Blob () вы можете «встроить» своего рабочего в тот же HTML-файл, что и ваша основная логика, создав дескриптор URL-адреса для рабочего кода в виде строки.

let blob = new Blob([
    "onmessage = function(e) { postMessage('msg from worker'); }"]);

// Obtain a blob URL reference to our worker 'file'.
let blobURL = window.URL.createObjectURL(blob);

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

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

В приведенном выше примере в идентификатор сценария «worker-1» я добавил код для веб-воркера, а затем в проанализированном сценарии JavaScript создал для него URL-адрес Blob.

Передача данных работникам и от них

Когда мы используем postMessage, мы передаем данные между веб-исполнителями и главной страницей. Эти данные копируются, а не разделяются между двумя страницами, то есть объекты сериализуются по мере их передачи рабочему, а затем десериализуются на другом конце. Большинство браузеров реализуют эту функцию как структурированное клонирование. Это кажется нормальным для передачи небольших данных, но для больших объемов данных это заметные накладные расходы.

Чтобы смягчить это снижение производительности, мы можем использовать объект Transferrable. С помощью переносимых объектов данные переносятся из одного контекста в другой. Это значительно повышает производительность отправки данных рабочему. Думайте об этом как о передаче по ссылке, если вы из мира C / C ++. Однако, в отличие от передачи по ссылке, версия из вызывающего контекста больше не доступна после передачи в новый контекст. Например, при передаче ArrayBuffer из вашего основного приложения в Worker исходный ArrayBuffer очищается и больше не может использоваться. Его содержимое передается в контекст Worker.

Для использования переносимых объектов используется следующая команда

worker.postMessage(arrayBuffer, [arrayBuffer]);

Первый аргумент - это данные, а второй - список элементов, которые следует передать.

Возможности, доступные веб-воркерам

Веб-воркеры имеют доступ только к подмножеству функций JavaScript из-за их многопоточной природы. Вот список функций:

⦁ Объект навигатора

⦁ Объект местоположения (только для чтения)

⦁ XMLHttpRequest

⦁ setTimeout () / clearTimeout () и setInterval () / clearInterval ()

⦁ Кэш приложения

⦁ Импорт внешних скриптов с помощью importScripts ()

⦁ Создание других веб-воркеров

⦁ Ограничения Web Worker

Веб-воркеры не имеют доступа к некоторым очень важным функциям JavaScript:

⦁ DOM (он не ориентирован на многопоточность)

⦁ Объект окна

⦁ Объект документа

⦁ Родительский объект

Случаи применения

Веб-воркеры обладают огромными способностями, но, как говорится, «С большой силой приходит большая ответственность». Точно так же мы должны быть осторожны при их использовании. Предпочтительно, когда фоновые задачи должны выполняться параллельно с основной задачей пользовательского интерфейса или выполняемые задачи должны быть скрыты от пользователя. Вот некоторые из других его вариантов использования:

⦁ Предварительная выборка и / или кеширование данных для последующего использования.

⦁ Подсветка синтаксиса кода или другое форматирование текста в реальном времени.

⦁ Проверка орфографии

⦁ Прогрессивные веб-приложения

⦁ Анализ видео или аудио данных.

⦁ Фоновый ввод-вывод или опрос веб-служб.

⦁ Обработка больших массивов или громоздких ответов JSON.

⦁ Фильтрация изображений в ‹canvas›.

⦁ Обновление многих строк локальной веб-базы данных.

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

Спасибо, что нашли время прочитать статью. В следующей статье я расскажу о Service Workers, другом, но очень полезном веб-воркере.