Рубрики
Без рубрики

Использование веб -работников для безопасного, одновременного JavaScript

Веб -работники предоставляют способ запустить код JavaScript за пределами единого потока … Tagged с анимацией, WebDev, HTML, JavaScript.

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

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

В противном случае интерактивность в киосках браузера.

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

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

Приложения, которые когда -то могли считаться «вычислительно интенсивными», теперь считаются не так уж и плохи.

Что вы имеете в виду, это не вакуум?

Но много раз мы рассматриваем только выполнение одного приложения, протестированного в среде разработки, при принятии решения о том, как эффективно выполнять код. В реальной системе в руках пользователя многие вещи могут выполняться одновременно.

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

Запуск нового работника так же просто, как указать файл, содержащий код JavaScript:

https://medium.com/media/54f116b9159f391940d2d175629ef406/href

Как только работник создается, он работает в отдельном потоке, независимо от основного потока браузера, выполняя любой код в сценарии, который ему дается. Браузер смотрит относительно местоположения текущей HTML -страницы для указанного файла JavaScript.

Данные передаются между работниками и основным потоком JavaScript с использованием двух дополнительных функций в коде JavaScript:

  • функция postmessage () на стороне отправки
  • Обработчик событий «сообщения» на приемной стороне

Обработчик событий сообщений получает аргумент события, как это делают другие обработчики событий; Это событие имеет свойство «данные», которое имеет любые данные, которые были переданы с другой стороны.

Это может быть двусторонняя связь: код в основном потоке может вызвать postmessage (), чтобы отправить сообщение работнику, и работник может отправлять сообщения обратно в основной потоко. Во всем мире в среде работника.

Очень простой поток в веб -работнике выглядел бы так: в HTML страницы сообщение отправляется работнику, и страница ждет ответа:

https://medium.com/media/c12b2bab56dc91432e763d8f65cd7498/href

Код работника ждет сообщение:

https://medium.com/media/45a95685acf3c88fe4161b5730d546d0/href

Приведенный выше код будет распечатать это на консоли:

Message posted from webworker: Worker running Message posted from webworker: Worker received data: {"data":"123456789"}

Ожидается, что работники будут долгое время, а не остановлены и начали

Несколько сообщений могут быть отправлены и получены между браузером и работником в течение жизни работника.

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

  • Отчетая изолированная глобальная среда для рабочей потока, отдельно от среды браузера
  • Пропустить обмен данными между основными и рабочими потоками в Postmessage () вызов

Каждая рабочая нить имеет отдельную изолированную глобальную среду, которая отличается от среды JavaScript страницы браузера. Работникам вообще не предоставляется никакого доступа ни к чему в среде JavaScript на странице, а не в DOM, ни в объектах «окно» или «документ».

У работников есть свои собственные версии некоторых вещей, такие как объект «Консоль» для регистрации сообщений в консоли разработчика, а также объект xmlhttprequest для выполнения запросов Ajax. Но кроме того, что код JavaScript, который работает в работнике, должен быть самостоятельным; Любой вывод из потока работника, который хотел бы использовать главное окно, должен быть передан обратно в качестве данных через функцию postmessage ().

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

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

Типичный вариант использования для веб -работника – это любая задача, которая может стать вычислительной дорогой в ходе его выполнения, либо путем употребления большого количества времени ЦП, либо заняв непредсказуемо длительное количество времени для доступа к данным.

Некоторые возможные варианты использования для веб -работников:

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

Время процессора – это простой вариант использования, но доступ к сети к ресурсам также может быть очень важен. Много раз сетевое общение через Интернет может выполняться в миллисекундах, но иногда сетевой ресурс становится недоступным, останавливаясь, пока сеть не будет восстановлена, или время запроса (что может занять 1–2 минуты, чтобы очистить).

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

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

Демонстрация: обнаружение столкновения игры

(Ремень в. Это длинный пример.)

Игры на основе HTML5, которые выполняются в веб-браузере, сейчас везде. Одним из центральных аспектов игр является вычисление движения и взаимодействия между частями игровой среды. Некоторые игры имеют относительно небольшое количество движущихся частей, и их довольно легко анимировать ( эмулятор Super Mario клон, кто -нибудь?). Но давайте рассмотрим более вычислительно тяжелый чехол.

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

Обнаружение границ относительно простое и быстрое для выполнения, но обнаружение столкновений может быть более требовательным вычислительно, так как оно растет примерно как квадрат числа шаров: для «n» шариков каждый шарик должен сравниваться с шариком друг друга, чтобы увидеть, чтобы увидеть шарики, чтобы увидеть, чтобы увидеть шарики друг с другом, чтобы увидеть друг друга, чтобы увидеть друг друга, чтобы увидеть друг друга, чтобы увидеть друг друга, чтобы увидеть друг друга, чтобы увидеть друг друга, чтобы увидеть друг друга, чтобы увидеть друг друга, чтобы увидеть шарики «n». Если их пути пересекались и должны быть отскакивают (что приводит к N Times N или N квадратным сравнениям).

Таким образом, для 50 шаров по заказу 2500 чеков должны быть сделаны; Для 100 шаров необходимы 10000 проверок (на самом деле это немного меньше, чем вдвое меньше, чем на то, если вы проверяете мяч N против Ball M, вам не нужно позже проверять мяч M против Ball N, но все же, может быть большое количество вычисления вовлечены).

Для этого примера определение границ и столкновений выполняется в отдельном потоке работников, и этот поток выполняется на скорости анимации браузера, в 60 раз в секунду (каждый вызов requestAnimationFrame ()). Определяется мировой объект, который содержит список шаровых объектов; Каждый шаровой объект знает его текущее положение и скорость (а также радиус и цвет, чтобы его нарисовали).

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

Мировой объект передается между клиентским кодом в браузере и потоком работника. Это относительно небольшой объект даже для нескольких сотен шаров (в 100 раз примерно 64 байта данных на байты данных). Таким образом, проблема здесь заключается в вычислительной нагрузке.

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

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

https://medium.com/media/f6c40876938c84253377e16dd08dfd0b/href

Код использует requestAnimationFrame () для запуска функции AnimationStep () в 60 раз в секунду, в период обновления дисплея. Шаг анимации состоит из «перемещения», обновления позиции каждого из шаров (и, возможно, направления), затем «рисунка», перерисовывающего холст с шариками в их новой позиции.

Чтобы использовать рабочую ветку для этого приложения, часть петли анимации «Перемещение» (код в World.move ()) будет перенесена на работника. Мировой объект будет передаваться в виде данных в поток работников через вызов Postmessage (), чтобы там можно было сделать вызов Move (). Мировой объект, безусловно, является то, что он должен передать, поскольку в нем есть список шаров и прямоугольную границу, в которой они должны оставаться внутри, и каждый шарик сохраняет всю информацию о его положении и скорости.

С изменениями, чтобы использовать работника, пересмотренная петля анимации выглядит следующим образом:

https://medium.com/media/ceaad1fc8d65f33b134d6abdc9e8f728/href

И сама рабочая нить просто выглядит так:

https://medium.com/media/616f4d9c423ad7950dcba253069dd455/href

Код здесь основан на рабочем потоке, чтобы принять мировой объект в Postmessage () из основного кода, а затем передайте мир обратно в основной код с обновленными позициями и скоростями. Помните, что браузер сделает копию мирового объекта, когда он входит в нить и из них – предположение здесь состоит в том, что время создания копии объекта мира значительно меньше, чем O (n ** 2) Расчеты столкновений (это действительно относительно небольшие данные, которые хранятся в «мире»).

Однако запуск кода на основе новой рабочей потока приводит к неожиданной ошибке:

Uncaught TypeError: world.move is not a function at collider-worker.js:10

Оказывается, что процесс копирования объекта в вызове Postmessage () скопирует свойства данных на объекте, но не прототип объекта Анкет Методы мирового объекта исключены из прототипа, когда он скопирован и передается работнику. Это часть «Структурированный алгоритм клона» , стандартный способ, который объекты копируются между основным потоком и веб -работником, также известным как сериализация .

Чтобы обойти это, я добавлю метод мирового класса для создания нового экземпляра (который будет иметь прототип с методами) и переназначу свойства данных из переданных данных, которые размещены в сообщении:

https://medium.com/media/aef82b783aa6949990eab49c9208b4d1/href

Попытка запустить анимацию с помощью этого исправления результатов в другой, аналогичной ошибке … основные объекты мяча в мировом списке дисплеев также должны быть восстановлены:

Uncaught TypeError: obj1.getRadius is not a function at World.checkForCollisions (collider.js:60) at World.move (collider.js:36)

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

Теперь в мировом классе:

https://medium.com/media/59924177d196d976647bcb5a3271cf35/href

А также Аналогичный метод восстановления offromData (), реализованный в классе мяча:

https://medium.com/media/5933f343c8f3a765b24b0afc1eaadb91/href

При этом анимация работает правильно, вычисляя «движения» каждого из, возможно, сотни шаров в потоке работников и отображая их обновленные позиции в 60 раз в секунду в браузере.

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

Демо: пороговые изображения

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

Эта демонстрация будет использовать Библиотека обработки изображений Написано в 2012 году Ильмари Хейккинен. Он потребует цветового изображения и преобразует его в двоичное черно -белое изображение, пороговое значение по промежуточному серому значению: пиксели, чье серого значения меньше, чем это значение казалось черным, больше, чем это значение кажутся белыми.

Пороговой код проходит через каждое значение (RGB), используя формулу, чтобы преобразовать ее в серое значение:

https://medium.com/media/12381c4c82b6280cc18c9d137f4b4387/href

Для изображения, которое изначально выглядит так:

Алгоритм порога создает двухтологическое черно -белое изображение, как это:

Кодепен для этой демонстрации можно найти Здесь Анкет

Даже для небольших изображений данные, а также вычисления могут быть большими. Изображение 640 на 480 содержит 307 200 пикселей, каждый из которых имеет четыре байта данных RGBA («A» для альфа или данных о прозрачности), в результате чего размер данных изображения до 1,2 МБ. План состоит в том, чтобы использовать веб -работника для итерации по каждому из пикселей и преобразовать его в новые значения RGB. Данные Pixel для изображения должны быть переданы из браузера в поток работника, и измененное изображение будет возвращено обратно. Было бы лучше не копировать эти данные каждый раз, когда они передаются туда -сюда между клиентским и рабочим потоком.

Расширение на вызов Postmessage () дает способ указать один или несколько свойств данных, которые передаются с помощью сообщения, которое должно передаваться с помощью ссылки, а не копировать. Похоже:

https://medium.com/media/f8e7adba2eac07ffcf3ac7da677357b0/href

Любой объект, который реализует передаваемый интерфейс, может быть указан здесь. «Data.buffer» объекта ImageData соответствует этому требованию – он имеет тип Uint8clampedArray (тип массива, предназначенный для хранения 8 -битных данных изображения). Imagedata – это то, что возвращается методом getimagedata () объекта контекста HTML5 Canvas.

В общем, несколько стандартных типов данных реализуют передаваемый интерфейс: ArrayBuffer, MessagePort и ImageBitmap. ArrayBuffer, в свою очередь, реализован рядом конкретных типов массива: Int8array, uint8array, uint8clampedarray, int16array, uint16array, int32array, uint32array, float32array, float64array.

Так что, если данные теперь передаются между потоками по ссылке, а не по значению, могут ли данные быть изменены в обоих потоках одновременно? Стандарты предотвращают это: когда данные передаются postmessage (), доступ к данным отключен (термин «стерилизованный» фактически используется в спецификациях) на стороне отправки, что делает его недоступным. Передача данных обратно через Postmessage () «Нейтеры» на стороне рабочей потока, но делает их доступными в браузере. Эта функция «стерилизации» реализована в двигателе JavaScript.

Резюме и последние мысли

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

Два примера продемонстрировали некоторые особенности веб -работников:

  • Основное двухстороннее сообщение, проходящее через вызовы postmessage () и слушатели “Сообщение”
  • Вычисляющий интенсивный пример: обнаружение границ и столкновений в анимации HTML5
  • Последний пример: пороговое значение изображения (как вычислительные, так и интенсивные данные), демонстрируя передачу больших массивов данных с помощью ссылки в PostMessage () функция

Попутно, в продемонстрированных примерах изучались несколько вопросов и деталей реализации веб -работников:

  • Процесс сериализации, который применяется при передаче объектов JavaScript в postmessage (), не копирует методы в прототипе объекта – какой -то код должен быть придуманен для восстановления этих
  • При передаче массива данных пикселей из метода getimagedata () свойство буфера объекта Pixel Data должно быть передано в Postmessage () Call (например, iMagedata.data.buffer, не iMagedata.data) – это буфер Реализует перенос

В настоящее время веб -работники поддерживаются большинством основных, нынешних браузеров. Chrome, Safari и Firefox поддерживают их примерно с 2009 года; Они поддерживаются на MSEDGE и были поддержаны в Internet Explorer со времен IE10.

Для совместимости с браузерами простая проверка для «if (typeof kafler)» может защитить код, который создает и использует работника, с альтернативным выполнением того же кода за пределами работника (в тайм -аут или рамке анимации).

Plug: Logrocket, DVR для веб -приложений

Logrocket это инструмент регистрации фронта, который позволяет вам воспроизводить проблемы, как будто они произошли в вашем собственном браузере. Вместо того, чтобы догадаться, почему возникают ошибки, или просить пользователей экрана и журнала дамп, Logrocket позволяет воспроизвести сеанс, чтобы быстро понять, что пошло не так. Он отлично работает с любым приложением, независимо от фреймворта, и имеет плагины для регистрации дополнительного контекста из Redux, Vuex и @ngrx/Store.

В дополнение к журналам Redux и состоянию регистрации журналы консоли Logrocket записывают, ошибки JavaScript, StackTraces, сетевые запросы/ответы с заголовками + BODES, метаданные браузера и пользовательские журналы. Он также придает DOM записывать HTML и CSS на странице, воссоздавая видеопроблемные видео даже самых сложных одностраничных приложений.

Попробуйте бесплатно.

Оригинал: “https://dev.to/bnevilleoneill/using-web-workers-for-safe-concurrent-javascript-3fpd”