Web Worker API

Определение и выполнение веб-воркера

Последнее обновление: 14.11.2023

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

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

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

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

Для создания веб-воркера применяется функция-конструктор Worker:

const worker = new Worker("worker.js");

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

Создаваемый функций Worker() веб-воркер еще называют выделенным веб-воркером (dedicated web worker).

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

Рассмотрим простейший пример. Определим для проекта на жестком диске папку, в которой создадим три файла:

  • index.html: главная страница приложения

  • worker.js: файл задачи веб-воркера

  • server.js: файл приложения сервера Node.js

Определение веб-страницы и создание веб-воркера

На странице index.html определим следующий код:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>METANIT.COM</title>
</head>
<body>
<script>
const worker = new Worker("worker.js");
</script>
</body>
</html>

Фактически здесь только создается объект веб-воркера, который будет выполнять код из файла "worker.js".

Определение кода веб-воркера

В файле worker.js определим для демонстрации простейший код:

let result = 1;
const intervalID = setInterval(work, 1000);

function work() {
  	result = result * 2;
	console.log("result=", result);
	if(result >= 32) clearInterval(intervalID);
}

Здесь с помощью функции setInterval() каждую секунду будет выполняться функция work. В функции work мы просто получаем значение переменной result на 2, сохраняем результат обратно в переменную result и текущий результат выводим на консоль. Когда result достигнет предела - числа 32, то останавливаем таймер, что приведет к завершению скрипта и соответственно задачи веб-воркера.

Определение сервера

Для коректной работы вею-страницы ее надо запускать с веб-сервера. И в данном случае в файле server.js определим код локального веб-сервера Node.js. Определим в нем следующий код:

const http = require("http");
const fs = require("fs");
    
http.createServer((request, response)=>{
    // получаем путь после слеша, слеш - первый символ в пути
    let filePath = request.url.substring(1);
    // если пустой путь, отправляем главную страницу index.html
    if(!filePath) filePath = "index.html";  
    // в качестве типа ответа устанавливаем html
    response.setHeader("Content-Type", "text/html; charset=utf-8;");
    fs.readFile(filePath, (error, data)=>{
        if(error){                              // если ошибка
            response.statusCode = 404;
            response.end("<h1>Resourse not found!</h1>");
        }   
        else{
            response.end(data);
        }
    });
}).listen(3000, ()=>console.log("Сервер запущен по адресу http://localhost:3000"));

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

const http = require("http");	// для обработки входящих запросов
const fs = require("fs");		// для чтения файлов с жесткого диска

Для создания сервера применяется функция http.createServer(). В эту функцию передается функция-обработчик, которая вызывается каждый раз, когда к серверу приходит запрос. Эта функция имеет два параметра: request (содержит данные запроса) и response (управляет отправкой ответа).

В функции-обработчике с помощью свойства request.url мы можем получить путь к ресурсу, к которому пришел запрос. Нам надо обрабатывать запросы к страницам "index.html" и "home.html" (а в перспективе к любым другим страницам html). Путь всегда начинается со слеша "/". Например, запрос к странице "home.html" будет представлять путь "/home.html". Соответственно, чтобы получить из запрошенного пути путь к файлам на жестком диске, нам надо убрать начальный слеш:

let filePath = request.url.substring(1);

Однако если запрос обращен к корню сайта, то путь состоит только из одного слеша - "/". Соответственно, если мы удалим этот слеш, то получим пустую строку. Поэтому если запрос идет к корню веб-приложения, то будем считать что запрос идет к главной странице - index.html:

if(!filePath) filePath = "index.html";

И поскольку в нашем случае ответ сервера будет представлять код html, то с помощью метода setHeader() устанавливаем для заголовка "Content-Type" значение "text/html":

response.setHeader("Content-Type", "text/html; charset=utf-8;");

То есть ответ сервера будет представлять html.

Далее с помощью функции fs.readFile считываем файл, к которому идет запрос. Первый параметр функции - адрес файла (в данном случае предполагается, что файл находится в одной папке с файлом сервера server.js). Второй параметр - функция, которая вызывается после считывания файла и получет его содержимое через свой второй параметр data. Вполне возможно, что запрошенного файла не окажется, и в этом случае отправляем ошибку 404:

fs.readFile(filePath, (error, data)=>{
    if(error){                              // если ошибка
        response.statusCode = 404;
        response.end("<h1>Resourse not found!</h1>");
    } 

Если ошибки нет, файл найден и успещно считан, то отправляем параметр data, который содержит данные файла:

else{
    response.end(data);
}

В конце с помощью функции listen() запускаем веб-сервер на 3000 порту. То есть сервер будет запускаться по адресу http://localhost:3000/

Запуск и тестирование приложения

Теперь в консоли перейдем к папке сервера с помощью команды cd и запустим сервер с помощью команды node server.js

C:\app>node server.js
Сервер запущен по адресу http://localhost:3000

После запуска сервера мы можем перейти в браузере по адресу http://localhost:3000, нам отобразится страница, в javascript-коде которой будет создан веб-воркер. Этот веб-воркер выполнит задачу, определенную в файле worker.js, а на консоли мы увидим результат этой работы:

Тип Worker в Web Worker API и параллельное выполнение фоновых задач в javascript

Ограничения веб-воркера

В примере выше в коде веб-воркера использовался таймер, создаваемый функцией setInterval(). Однако не всю функциональность стандартного браузерного JavaScript мы можем использовать в задачах веб-воркера. Так, веб-воркеры не имеют доступа к DOM и к объекту window. Тем не менее часть возможностей объекта window (свойств и методов) доступны для веб-воркера (как в случае с функцией setInterval()). В частности, доступны следующие функции:

  • atob()

  • btoa()

  • clearInterval()

  • clearTimeout()

  • queueMicrotask()

  • setInterval()

  • setTimeout()

  • structuredClone()

  • requestAnimationFrame() (только для выделенных веб-воркеров)

  • cancelAnimationFrame() (только для выделенных веб-воркеров)

Также для веб-воркеров доступны следующие свойства объекта window:

  • console

  • location

  • navigator

  • indexDB

Кроме того, веб-воркеры могут использовать следующие API:

  • Barcode Detection API

  • Broadcast Channel API

  • Cache API

  • Channel Messaging API

  • Console API

  • Web Crypto API (например, Crypto)

  • CSS Font Loading API

  • CustomEvent

  • Encoding API (например, TextEncoder, TextDecoder)

  • Fetch API

  • FileReader

  • FormData

  • ImageBitmap

  • ImageData

  • IndexedDB

  • Media Source Extensions API

  • Network Information API

  • Notifications API

  • OffscreenCanvas (и API для работы с контекстом элемента canvas)

  • Performance API

  • Server-sent events

  • ServiceWorkerRegistration

  • URL API

  • WebCodecs_API

  • WebSocket

  • XMLHttpRequest

Получение веб-воркера и self

С помощью слова self в скрипте веб-воркера (worker.js) мы можем обращаться к объекту веб-воркера:

console.log(self); // получим данные о веб-воркере

let result = 1;
const intervalID = setInterval(work, 1000);

function work() {
  	result = result * 2;
	console.log("result=", result);
	if(result>= 32) clearInterval(intervalID);
}

Остановка работы веб-воркера

Веб-воркер может работать долго вплоть до бесконечности, пока пользователь находится на странице. И может возникнуть вопрос, как завершить выполнение веб-воркера. Для этого интерфейс Worker определяет метод terminate(). Например, изменим код веб-страницы index.html следующим образом:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>METANIT.COM</title>
</head>
<body>
<button id="btn">Stop</button>
<script>
const worker = new Worker("worker.js");
// по нажатию на кнопку останавливаем работу веб-воркера
document.getElementById("btn").addEventListener("click", ()=> {
    worker.terminate();
    console.log("web worker stopped");
});
</script>
</body>
</html>

Здесь на веб-странице определена кнопка, по нажатию на которую происходит остановка веб-воркера.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850