Статьи

Совет: веб-работники JavaScript переносят тяжелую работу в фоновый режим

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


На земле HTML5 у нас есть несколько очень интересных API. Некоторые из них — например, веб-работники — полезны для повышения производительности, что очень важно как для приложений, так и для игр. Но как веб-работники … ну, работают?

Каждый экземпляр веб-работника создает другой поток, в котором работает ваш JavaScript. Вы создаете один экземпляр так:

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

Здесь «filename.js» — это имя файла, содержащего ваш скрипт. Поскольку работники являются отдельными средами, вы не можете использовать код, встроенный непосредственно в HTML; Вы должны использовать отдельный файл.


У рабочих нет доступа к DOM страницы или глобальному объекту, так как они общаются с сайтом? Это просто. Когда вы хотите отправить некоторые данные со своей страницы в Worker, вы вызываете postMessage() .

Для этого требуется один параметр: данные для отправки, которые могут быть либо строкой, либо объектом, доступным для анализа в формате JSON (это означает, что вы не можете передавать функции или циклические ссылки, или вы получите DOM_EXCEPTION ). В некоторых браузерах существует проблема с объектами, поэтому всегда лучше вручную анализировать объект с помощью JSON.parse() чтобы вам не приходилось беспокоиться о неполных реализациях.

То же самое происходит, если вы отправляете данные от Worker на страницу: просто вызовите postMessage() для self , который ссылается на глобальную область Worker. (Вы делаете это внутри сценария работника, конечно).

Затем для получения данных необходимо прикрепить onmessage события onmessage . Есть два способа сделать это, как с обычными событиями для элементов DOM; вы можете либо напрямую назначить некоторую функцию свойству onmessage , либо использовать addEventListener() .

1
2
3
4
5
6
7
8
9
// First way:
worker.onmessage = function (e) {
    console.log(e.data);
}
 
// Second way:
worker.addEventListener(‘message’, function (e) {
    console.log(e.data);
});

Это ваш выбор, какой метод использовать. В любом случае, параметр функции будет объектом event , и данные, отправленные с помощью postMessage() будут переданы через свойство data этого события.


Хорошо, но что если нам нужно использовать какую-нибудь внешнюю библиотеку? У нас нет доступа к DOM или глобальной области видимости, поэтому мы не можем просто внедрить скрипт.

Конечно, нам не нужно — для этого есть функция. Он называется importScripts() и принимает один или несколько аргументов: имена сценариев для загрузки внутри области Worker. Вы должны знать, что скрипты, переданные в эту функцию, загружаются в случайном порядке, но они будут выполняться так, как указано, и выполнение скриптов будет приостановлено до тех пор, пока они не будут загружены.

1
2
importScripts(‘one-lib.js’);
importScripts(‘first-lib.js’, ‘second-lib.js’, ‘third-lib.js’);

Вы можете использовать importScripts любом месте вашего кода, что упрощает создание запросов JSONP внутри Workers, как мы сделаем в следующем примере.


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

Пример сценария (я включил только код Worker, остальное легко сделать) получит последние 100 твитов от @envatoactive (нам нужно установить счетчик 121 вместо 100, так как Tweeter API отправляет меньше твитов, чем просил — не спрашивайте меня почему, я не знаю).

Вот код, который будет находиться внутри самого файла сценария Web Worker:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Helper function for processing the data
var process = function (data) {
    // Iterate through the data;
    for (var i = 0, v; v = data[i]; i++) {
        // And pass Tweet’s text to the page
        self.postMessage({ text: v.text });
    }
    // After work is done, let the page know
    self.postMessage(«finished»);
}
 
// Attach event listener to handle messages
self.addEventListener(‘message’, function (event) {
    // Check if command sent was ‘start’
    // Not necessary here, but may be useful later
    if (event.data == «start») {
        // Reply to the page that we started the work
        self.postMessage(«started»);
        // Core of the script, get the Tweets
        // The callback parameter specifies the function to execute after the request is done
        // (We call the process() function, defined above.)
        // Count needs to be 121 because Tweeter API is sending lower amount of data than requested
        importScripts(«http://twitter.com/statuses/user_timeline/envatoactive.json?callback=process&count=121»);
    }
});

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

Теперь попробуйте вставить следующий эквивалентный код, который не использует веб-работников, вместо заголовка пустой страницы и обратите внимание на задержку. (Это все еще мало, но представьте, если вы получаете не 100, а 100 000 твитов):

01
02
03
04
05
06
07
08
09
10
<script type=»text/javascript»>
    var process = function (data) {
        // Iterate through the data;
        for (var i = 0, v; v = data[i]; i++) {
            // And log Tweet’s text to the console
            console.log(v.text);
        }
    }
</script>
<script src=»http://twitter.com/statuses/user_timeline/envatoactive.json?callback=process&count=121″></script>

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

Я надеюсь, что вы узнали что-то новое из этой статьи — может быть, вы будете использовать Workers в вашем следующем проекте? Если у вас есть какие-либо вопросы или проблемы, пожалуйста, прокомментируйте ниже.