Инструмент производительности JavaScript — Web Worker

JavaScript

Эта статья моя последняя статья"Уголок ПВА"Расширение представляет Web Worker, связанный с Service Worker в PWA, я надеюсь, что это поможет вам, и, пожалуйста, дайте мне больше советов. Статьи на темы PWA будут выходить одна за другой, так что следите за обновлениями.

Введение

Web Worker (рабочий поток) — это концепция, предложенная в HTML5, которая делится на два типа: выделенный поток (Dedicated Web Worker) и общий поток (Shared Web Worker). Выделенный поток может использоваться только сценарием, который его создал (выделенный поток для основного потока), в то время как общий поток может использоваться в разных сценариях (общий поток для нескольких основных потоков).

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

использовать

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

  • ленивая загрузка
  • Анализ текста
  • Обработка данных потокового мультимедиа
  • холст графика рисунок
  • Обработка изображения
  • ...

Нужно обратить внимание на точку

  • Гомологическая рестрикция
  • Не удается получить доступ к узлу DOM
  • Работает в другом контексте, не может использовать объект Window
  • Работа Web Worker не влияет на основной поток, но все же ограничена узким местом одиночного потока основного потока при взаимодействии с основным потоком. Другими словами, если рабочий поток часто взаимодействует с основным потоком, основной поток все равно может заблокировать страницу из-за необходимости обработки взаимодействия.
  • Общие потоки могут вызываться несколькими контекстами просмотра, но все эти контексты просмотра должны иметь одно и то же происхождение (один и тот же протокол, хост и номер порта).

поддержка браузера

Согласно статистике CanI Use the site, в настоящее время около 93,05 процента браузеров поддерживают выделенный поток.image

А для общих тредов его поддерживают только около 41,66% браузеров.image

Поскольку конструкторы выделенных и общих потоков содержатся в объекте окна, мы можем судить о поддержке браузера, прежде чем использовать оба.

if (window.Worker) {
    // ...
}
if (window.SharedWorker) {
    // ...
}

создание темы

Специальная ветка отWorker()Создание метода может принимать два параметра, первый параметр — это расположение требуемого скрипта, а второй параметр — необязательный объект конфигурации, который можно указатьtype,credentials,nameтри свойства.

var worker = new Worker('worker.js')
// var worker = new Worker('worker.js', { name: 'dedicatedWorker'})

Использование общего потокаShared Worker()Создание метода также поддерживает два параметра, использование такое же, какWorker()Последовательный.

var sharedWorker = new SharedWorker('shared-worker.js')

Стоит отметить, что, поскольку Web Worker имеет такое же ограничение происхождения, к нему также необходимо получить доступ, запустив локальный сервер при локальной отладке, используяfile://Если протокол открыт напрямую, будет выдано исключение.

Передача данных

И рабочий поток, и основной поток проходятpostMessage()способ отправить сообщение черезonmessageСобытия получают сообщения. В этом процессе данные не передаются, а копируются. Стоит отметить, чтоErrorа такжеFunctionОбъекты не могут быть скопированы алгоритмом структурированного клонирования, и попытка сделать это приведет к броскуDATA_CLONE_ERRисключение. Кроме того,postMessage()За один раз можно отправить только один объект. Если вам нужно отправить несколько параметров, вы можете обернуть параметры в массив или объект и передать их.

оpostMessage()а алгоритм структурированного клонирования (Thestructured clone algorithm) будет описан в конце этой статьи.

Ниже приведен пример передачи данных выделенного потока.

// 主线程
var worker = new Worker('worker.js')
worker.postMessage([10, 24])
worker.onmessage = function(e) {
    console.log(e.data)
}

// Worker 线程
onmessage = function (e) {
    if (e.data.length > 1) {
        postMessage(e.data[1] - e.data[0])
    }
}

В рабочем потокеselfа такжеthisОба представляют глобальные объекты для дочерних потоков. для мониторингаmessageСобытия, следующие четыре написания эквивалентны.

// 写法 1
self.addEventListener('message', function (e) {
    // ...
})

// 写法 2
this.addEventListener('message', function (e) {
    // ...
})

// 写法 3
addEventListener('message', function (e) {
    // ...
})

// 写法 4
onmessage = function (e) {
    // ...
}

основной нить черезMessagePortДоступ к выделенным и общим темам. Порт выделенного потока автоматически устанавливается при создании потока и не отображается. В отличие от выделенных потоков, общие потоки должны иметь открытые порты перед передачей сообщений. на MDNMessagePortоstart()Описание метода такое:

Starts the sending of messages queued on the port (only needed when using EventTarget.addEventListener; it is implied when using MessagePort.onmessage.)

Это предложение было проверено и может быть понято какstart()метод сaddEventListenerиспользуются вместе. если мы выберемonmessageДля мониторинга событий он будет неявно вызыватьсяstart()метод.

// 主线程
var sharedWorker = new SharedWorker('shared-worker.js')
sharedWorker.port.onmessage = function(e) {
    // 业务逻辑
}
var sharedWorker = new SharedWorker('shared-worker.js')
sharedWorker.port.addEventListener('message', function(e) {
    // 业务逻辑
}, false)
sharedWorker.port.start() // 需要显式打开

При доставке сообщения,postMessage()Методы иonmessageСобытия должны вызываться через объект порта. Кроме того, в потоке Worker необходимо использоватьonconnectСобытие прослушивает изменения порта и отвечает обработчиком сообщений порта.

// 主线程
sharedWorker.port.postMessage([10, 24])
sharedWorker.port.onmessage = function (e) {
    console.log(e.data)
}

// Worker 线程
onconnect = function (e) {
    let port = e.ports[0]

    port.onmessage = function (e) {
        if (e.data.length > 1) {
            port.postMessage(e.data[1] - e.data[0])
        }
    }
}

близкий работник

можно использовать в основном потокеterminate()метод или использование в рабочем потокеclose()способ закрыть воркер. Эти два метода эквивалентны, но более рекомендуемым является использованиеclose(), чтобы предотвратить случайное завершение работы рабочих потоков. Как только рабочий поток закрывает рабочий поток, рабочий больше не будет отвечать.

// 主线程
worker.terminate()

// Dedicated Worker 线程中
self.close()

// Shared Worker 线程中
self.port.close()

обработка ошибок

Может быть установлен в основном потоке или в рабочем потокеonerrorа такжеonmessageerrorФункция обратного вызова для обработки ошибки. в,onerrorВ рабочемerrorВыполняется, когда событие срабатывает и всплывает,onmessageerrorЗапускается, когда сообщение, полученное Worker, не может быть десериализовано (я пробовал и не могу запустить егоonmessageerrorсобытие, если используется в рабочем потокеpostMessageМетоды, передающие объект Error или Function, будут иметь приоритет, поскольку они не могут быть сериализованы.onerrorзахват метода вообще без входа в процесс десериализации).

// 主线程
worker.onerror = function () {
    // ...
}

// 主线程使用专用线程
worker.onmessageerror = function () {
    // ...
}

// 主线程使用共享线程
worker.port.onmessageerror = function () {
    // ...
}

// worker 线程
onerror = function () {

}

Загружать внешние скрипты

Веб-воркер предоставляетimportScripts()чтобы иметь возможность загружать внешние файлы скриптов в Worker.

importScripts('script1.js')
importScripts('script2.js')

// 以上写法等价于
importScripts('script1.js', 'script2.js')

дочерний поток

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

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

Встроенный рабочий

Нет ярлыка может сделать свой вид кода, как работник<script>Элементы встроены в веб-страницы, но мы можемBlob()Разберите рабочий код на странице.

<script id="worker" type="javascript/worker">
// 这段代码不会被 JS 引擎直接解析,因为类型是 'javascript/worker'

// 在这里写 Worker 线程的逻辑
</script>
<script>
    var workerScript = document.querySelector('#worker').textContent
    var blob = new Blob([workerScript], {type: "text/javascript"})
    var worker = new Worker(window.URL.createObjectURL(blob))
</script>

О сообщенииСообщение

В Web Worker алгоритм структурированного клонирования используется для обмена данными между рабочим потоком и основным потоком. Алгоритм структурированного клонирования — это алгоритм, который создает клоны путем рекурсивного ввода объектов, избегая бесконечных циклов обхода за счет сохранения карты ранее посещенных ссылок. Этот процесс можно понимать как использование на стороне отправителя чего-то вродеJSON.stringfy()Метод сериализует параметры на стороне получателя, используя что-то вродеJSON.parse()способ десериализации.

Однако после передачи данных необходимо пройти через сериализацию и де сериализацию, если большое количество данных, то сам процесс также может вызвать проблемы с производительностью. Поэтому работника предложилTransferable ObjectsКонцепция, когда объем данных велик, мы можем выбрать передачу данных в основном потоке непосредственно в рабочий поток. Стоит отметить, что эта передача завершена, как только данные будут успешно переданы, основной поток не сможет получить доступ к данным. Этот процесс передачи еще продолжаетсяpostMessageпередавать.

postMessage(message, transferList)

Например, передайте объект ArrayBuffer

let aBuffer = new ArrayBuffer(1)
worker.postMessage({ data: aBuffer }, [aBuffer])

контекст

Работник работает вWorkerGlobalDataScopeв контексте. КаждыйWorkerGlobalDataScopeобъекты разныеevent loop. этоevent loopНет связанного контекста браузера (контекст просмотра), его очередь задач — это только события (events), обратные вызовы (callbacks) и сетевые действия (сетевая активность).

КаждыйWorkerGlobalDataScopeИмеетсяclosingфлаг, когда этот флаг установлен вtrue, очередь задач будет отбрасывать задачи, которые попытаются присоединиться к очереди задач позже, и задачи, уже находящиеся в очереди, не будут затронуты (если не указано иное). При этом таймер перестанет работать, а все отложенные фоновые задачи будут удалены.

Функции и классы, которые можно использовать в Worker

Поскольку контекст работы Worker отличается от обычного контекста браузера, он не может получить доступ к окну и связанным с ним API-интерфейсам, а также не может напрямую манипулировать DOM. Работник обеспечиваетWorkerNavigatorа такжеWorkerLocationинтерфейс, они соответственно в окнеNavigatorа такжеLocationподмножество . Кроме того, Worker также предоставляет различные интерфейсы, включая время, хранилище, сеть, рисование и т. д. Некоторые из них перечислены ниже.Документация MDN.

зависит от времени

  • clearInterval()
  • clearTimeout()
  • setInterval()
  • setTimeout

Связанный с работником

  • importScripts()
  • close()
  • postMessage()

Связанные с хранением

  • Cache
  • IndexedDB

Связанные с сетью

  • Fetch
  • WebSocket
  • XMLHttpRequest

Ссылки по теме

Ссылаться на

Расширенное чтение