Главная » Статьи » Повышение производительности с помощью Web Workers

Повышение производительности с помощью Web Workers

От автора: пошаговое руководство по имитации многопоточности в JavaScript с помощью
Web Workers.

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

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

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

Для борьбы с блокировками у нас есть несколько инструментов. Одним из таких инструментов являются веб-воркеры. Что такое веб-воркеры?

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

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

Туториал

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

Для начала нам понадобятся два скрипта: основной скрипт и скрипт воркера. Я собираюсь присвоить имя index.js основному скрипту и worker.js — скрипту веб-воркера. Код скрипта index.js выглядит так:

var i; for(i=0; i<=2000; i++){ console.log(i);
} console.log("---------------EXECUTED ------------------")

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

Повышение производительности с помощью Web Workers

Для выполнения инструкции console.log(«—-EXECUTED—») необходимо дождаться полного завершения предыдущей инструкции. В этом случае цикл for выполнил 2000 итераций, прежде чем выполнился console.log(«—-EXECUTED—»).

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

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

Реализуем веб-воркер

В файл index.js давайте внесем несколько изменений:

var webWorker = new Worker("worker.js"); console.log("---------------EXECUTED ------------------");

Во-первых, мы создаем веб-воркер. Вы можете назвать его как угодно. Я назвал своего веб-воркера webWorker. А справа от = мы просто пишем new Worker и путь к файлу скрипта в кавычках.

Как вы могли заметить, отсутствует цикл for, выполняющий 2000 итераций. Поместим его в наш файл worker.js, чтобы веб-воркер мог с ним работать. Оставим оператор журнала консоли в конце. В файле веб-воркера должен быть только цикл for.

var i; for(i=0; i<=2000; i++){ console.log(i);
}

Давайте запустим наш код.

Повышение производительности с помощью Web Workers

Обратите внимание, как console.log(» — — — — — — — -EXECUTED — — — — — — — — — «); выполняется сразу же в начале. Это потому, что два скрипта: index.js и worker.js работают одновременно, параллельно. Вот почему веб-воркеры являются мощными инструментами.

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

Связь между двумя скриптами

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

Мы можем сделать это с помощью функций onmessage() и postMessage(). Функция postMessage() — это то, как вы отправляете данные другому скрипту. А функция onmessage() — это то, как скрипт получает данные; функция onmessage() активируется, когда другой скрипт отправляет данные с помощью postMessage().

Давайте попробуем. Файл index.js выглядит так:

var webWorker = new Worker("worker.js");
var customer = { fName: "Kyle", lName: "De Guzman", age: "21", city: "Vegas"
} webWorker.postMessage(customer);
webWorker.onmessage = function (response){ console.log(response.data.result)
}

Мы создаем JavaScript объект с именем customer. Он содержит имя, фамилию, возраст и город. Затем мы обращаемся к функции postMessage(). Она позволяет нам отправлять данные в скрипт worker.js. В этом случае мы отправляем данные в виде объекта customer.

Затем мы получаем доступ к функции onmessage(), которая активируется после отправки ответа worker.js. Эта функция имеет параметр под названием response. Response — это данные, которые worker.js отправляет нам обратно. Двигаясь дальше, давайте посмотрим на файл worker.js.

this.onmessage=function(response){ var sentence = "Hello " + response.data.fName + " " + response.data.lName; this.postMessage({result: sentence});
}

Начнем с onmessage(). По сути, скрипт веб-воркера активируется, как только основной скрипт отправляет данные. Если вы помните, основной скрипт отправлял информацию о customer.

В этом случае данные отправляются под именем response. Вы можете изменить его на любое другое имя, которое захотите. Затем для доступа к ответу мы используем response.data.

Поскольку ответ имеет форму объекта, мы можем написать: respone.data.fName и response.data.lName. Если бы отправленные данные были бы строкой, числом или логическим значением, вам просто нужно было бы написать response.data.

В завершении работы скрипта веб-воркера мы используем postMessage(). Опять же, это используется для отправки данных. Как показано, данные, которые мы отправляем обратно, имеют форму объекта. Вы можете полностью отправить данные обратно в виде строки, если хотите. Запустим наш код.

Повышение производительности с помощью Web Workers

Как видите, мы успешно обменивались данными между двумя скриптами. Вот и все! Для получения дополнительной информации об API веб-воркеров ознакомьтесь с официальной документацией MDN.

Автор: Kyle DeGuzman

Источник: blog.bitsrc.io

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен