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

Мы можем добиться многопоточности в JavaScript с помощью HTML Web Workers API.

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

Как это началось?

Еще в 2015 году я работал над продуктом, я использовал стек технологий React и Flux.

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

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

  • Большой размер DOM
  • Увеличение краски и
  • Блокировка основного потока.

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

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

Я начал отладку проблемы, открыл инструменты разработчика и выяснил причину сбоя.

В DOM были тысячи элементов SVG.
Я использовал библиотеку C3, которая использует SVG для рисования диаграмм, и если у вас есть тысячи точек данных для рисования, размер DOM будет увеличиваются, так как использование ЦП, вызывая сбой браузера.

Используйте Canvas.

При возникновении любых проблем мы всегда обращаемся за помощью к Google и обнаруживаем, что я могу использовать холст для рисования диаграмм, поскольку он не увеличивает размер DOM.
Обнаружил эту библиотеку под названием chart.js , он рисует диаграмму на холсте и не увеличивает размер и элементы модели DOM.

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

К сожалению, версия библиотеки не поддерживает обновление живых диаграмм, и я перестал использовать chart.js.

HighCharts - Спаситель

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

Эта библиотека может отображать миллион точек данных на графике.

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

Чтобы нарисовать тысячи точек данных, мне пришлось сделать тысячи запросов.

Детализация:
Панель управления с выбором даты, где вы выбираете дату начала как 1 января 2020 года и дату окончания как 31 января 2020 года, и вы хотите рисовать диаграмму с интервалом в 5 минут. в течении месяца.

Это означает, что на диаграмме нужно будет нарисовать 43800 (приблизительно) точек данных

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

Как я это исправил?

Чтобы уменьшить время отклика API, я подумал делать запрос ajax от клиента (UI) каждые 5 минут.

Пример

mapi.com/charts?startDate=1Jan2020,12:00&endDate=1Jan2020,12:05
mapi.com/charts?startDate=1Jan2020,12:05&endDate=1Jan2020,12:10
mapi.com/ диаграммы? startDate = 1Jan2020,12: 10 & endDate = 1Jan2020,12: 15
….
….
mapi.com/charts?startDate=31Jan2020,23:55&endDate=31Jan2020,24:00

Это помогло мне сократить время отклика API, поэтому теперь мы можем рисовать диаграмму быстрее.

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

Как нам помог Web Worker?

Я читал в Интернете о том, как сократить время основного потока, и узнал, что могу использовать веб-воркеров.

Если вы хотите узнать, как работает веб-воркер, прочтите здесь.

Пул веб-воркеров

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

Поэтому мне нужен был пул веб-воркеров, каждый из которых будет делать разные запросы ajax (API), например

Сотрудник A
mapi.com/charts?startDate=1Jan2020,12:00&endDate=1Jan2020,12:05

Рабочий B
mapi.com/ диаграммы? startDate = 1Jan2020,12: 05 & endDate = 1Jan2020,12: 10

Рабочий C
mapi.com/charts?startDate=1Jan2020,12:10&endDate=1Jan2020,12:15

Скажем, я создал одного веб-воркера A, этот воркер сделает вызов API для получения данных в течение первых 5 минут с даты начала, и как только ответ API станет доступен, воркер A отправит данные обратно в основной поток.

Проверить реализацию

Как вы можете проверить, мы запускаем цикл while до 60, который создаст 60 веб-воркеров из основного потока, и мы увеличиваем время начала и окончания на каждые 5 минут. В рабочем файле я делаю вызов ajax каждые 5 минут.

С помощью описанного выше подхода я понял, как создать несколько запросов из рабочего потока.
Но была еще одна проблема: данные из backend API должны быть реструктурированы в соответствии с требованиями highcharts, а обработка данных все еще блокировал мой основной поток.

Итак, я определил тип рабочего

  • Один из типов воркеров, отвечающих за вызовы API
  • Другой будет отвечать за обработку данных

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

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

Проблема еще не была решена, поскольку API-интерфейсу требуется 55–58 секунд для получения полных данных для всех интервалов, а мы хотели сделать это менее чем за 10 секунд.

Увеличение имени хоста сокращает время загрузки.

На данный момент я был доступен с 60 веб-воркерами, работающими вместе, как показано на изображении выше.

Но я использовал http1.1 , а браузер может разрешить только 6 запросов на хост.

Я решил увеличить свое имя хоста до 10 и немного изменил мой подход,

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

Рабочий A выполнит вызов ajax на http://test1.sample-site.com
Рабочий B выполнит вызов ajax на http://test2.sample-site.com
Рабочий C выполнит вызов ajax на http://test3.sample-site.com

Реализация

У нас есть массив serverIp, в котором несколько URL-адресов, начиная с 1 и заканчивая 10.

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

Благодаря такому подходу мы почти сократили время загрузки, а вся операция запроса и ответа API выполнялась в течение 10–15 секунд.

Кроме того, мы кэшируем ответ API для каждого интервала, что помогло сократить время ответа API.

Эта проблема заняла у меня почти месяц, чтобы выяснить, какие библиотеки использовать, как уменьшить объем работы основного потока, размер DOM и т. Д.

Вот полный рабочий процесс, как каждый рабочий подключается и общается с основным потоком.

Надеюсь, вам понравилась эта статья.

Спасибо!

P.S. 👋 Привет, я Аатиф! Если вам это понравилось, подписывайтесь на меня в твиттере!