Всем известно, что в HTML 5 добавлено множество API, включая Web Worker. Использование ES5 для написания связанного кода с обычными js-файлами не должно вызвать проблем. Его нужно запускать только в браузерах, поддерживающих H5.
Что, если нам нужно использовать Web Worker в комбинированной среде ES6+Webpack? На самом деле это тоже очень удобно, просто нужно обращать внимание на отдельные точки, а потом записывать ямы, на которые я наступал.
Что касается базовых знаний и базового API Web Worker, то я поставлю его в конец для читателей, которые еще не знакомы с ним или не пользовались системой.
1. Быстро создать инженерную среду
Предположим, у вас уже есть среда разработки кода ES6+Webpack, и она может работать без сбоев; если нет, вы можете клонировать мой репозиторий github:GitHub.com/IR M-GitHub/…
2. Установите и используйте рабочий загрузчик
2.1 Зависимости установки:
$ npm install -D worker-loader
# 或
$ yarn add worker-loader --dev
2.2 Использовать worker-loader прямо в коде
// main.js
var MyWorker = require("worker-loader!./file.js");
// var MyWorker = require("worker-loader?inline=true&fallback=false!./file.js");
var worker = new MyWorker();
worker.postMessage({a: 1});
worker.onmessage = function(event) { /* 操作 */ };
worker.addEventListener("message", function(event) { /* 操作 */ });
Преимущества: файл сценария для написания рабочей логики может быть назван произвольно, главное, чтобы он был передан вworker-loader
можно обрабатывать в середине;
Недостаток: каждый раз, когда вводится скрипт-файл рабочей логики, показанный выше код нужно написать один раз, а «воркер-загрузчик!» нужно написать еще N(N>=1) раз.
2.3 Представлено в файле конфигурации веб-пакетаworker-loader
{
module: {
rules: [
{
// 匹配 *.worker.js
test: /\.worker\.js$/,
use: {
loader: 'worker-loader',
options: {
name: '[name]:[hash:8].js',
// inline: true,
// fallback: false
// publicPath: '/scripts/workers/'
}
}
}
]
}
}
При этом может быть предусмотрена конфигурацияinline
собственностьtrue
Встроить работника как большой двоичный объект;
Обратите внимание, что для браузера будет дополнительно создан встроенный режим.chunk
, даже для браузеров, не поддерживающих встроенных исполнителей; если такие браузеры хотят отключить это поведение, просто установитеfallback
параметр установлен наfalse
Вот и все.
3. Та же политика происхождения
Web Worker строго придерживается политики одного и того же происхождения.Если статические ресурсы веб-пакета и код приложения имеют разное происхождение, они, скорее всего, будут заблокированы браузером, и этот сценарий происходит часто. Есть два решения для Web Workers, чтобы столкнуться с этой ситуацией.
3.1 Первый
установивworker-loader
опционный параметрinline
Вставьте работника в формат данных BLOB-объектов вместо загрузки файла скрипта, чтобы использовать работника:
App.js
import Worker from './file.worker.js';
webpack.config.js
{
loader: 'worker-loader'
options: { inline: true }
}
3.2 Второй
установивworker-loader
опционный параметрpublicPath
Чтобы переписать URL-адрес загрузки рабочего сценария, конечно, сценарий также должен храниться в том же месте:
App.js
// This will cause the worker to be downloaded from `/workers/file.worker.js`
import Worker from './file.worker.js';
webpack.config.js
{
loader: 'worker-loader'
options: { publicPath: '/workers/' }
}
4. В режиме devServer сообщается об ошибке «окно не определено».
Если используетсяwebpack-dev-server
Если запущен локальный сервер отладки, в консоли может появиться сообщение об ошибке: «Uncaught ReferenceError: окно не определено»
Так или иначе, я столкнулся с этим, и я долго искал безрезультатно.В это время я умылся и успокоился, чтобы исследовать проблему.worker-loader
,webpack-dev-server
а такжеwebpack
Я нашел это в выпусках репозитория github и, наконец, нашелwebpack
Вопрос друга по коду был найден в репозитории github, и был дан официальный ответ:
Просто добавьте пару свойств под вывод в файле конфигурации webpack:globalObject: 'this'
output: {
path: DIST_PATH,
publicPath: '/dist/',
filename: '[name].bundle.[hash:8].js',
chunkFilename: "[name].chunk.[chunkhash:8].js",
globalObject: 'this',
},
5. Фон, на котором появляется веб-воркер
Движок JavaScript работает в одном потоке, а трудоемкие операции ввода-вывода в JavaScript обрабатываются как асинхронные операции, включая ввод-вывод с помощью клавиатуры, мыши, события ввода-вывода, размер окнаresize
события, таймеры (setTimeout
,setInterval
), события, обратные вызовы сетевого ввода-вывода запроса Ajax и т. д. Когда возникают эти асинхронные задачи, они помещаются в очередь событийных задач браузера и выполняются одна за другой по принципу «первым пришел — первым вышел», когда поток выполнения среды выполнения JavaScript простаивает, но в конце концов , это все еще один поток.
Обычно достаточно асинхронного программирования (promise
,async/await
), при столкновении с очень сложными операциями, такими как оптимизация или преобразование распознавания изображений, реализация игрового движка H5, операции алгоритма шифрования и дешифрования и т. д., постепенно будут отражаться их недостатки. Длительно работающий js-процесс может привести к тому, что браузер заморозит пользовательский интерфейс и ухудшит работу пользователя. Есть ли способ отделить сложный расчет от кода бизнес-логики, чтобы расчет можно было запустить, не блокируя пользовательский интерфейс для получения обратной связи?
Стандарт HTML5 передал спецификацию Web Worker, которая определяет набор API-интерфейсов, позволяющих запускать js-программу в другом потоке, отличном от основного. Рабочие потоки позволяют разработчикам писать фоновые программы, которые могут работать в течение длительного времени, не прерываясь пользователями, выполнять транзакции или логику и в то же время обеспечивать своевременный отклик страницы на запросы пользователей.Заморозить пользовательский интерфейс.
5. Типы веб-воркеров
Я всегда думал, что есть только один тип, а типов рабочих может быть несколько. Ответ положительный, его можно разделить на два типа:
- Преданный работник, преданный веб-работник
- Общий рабочий, общий веб-воркер
Доступ к «частному работнику» может получить только страница, которая его создала, в то время как «общий работник» может использоваться на одной и той же странице, открытой на нескольких вкладках браузера.
В js-кодеWoker
Представитель классаDedicated Worker
;Shared Worker
Представитель классаShared Web Worker
.
Я написал следующий пример кода непосредственно в ES5. Вышеизложенное научило вас использовать его в среде ES6 + Webpack. Каждый должен практиковать эту миграцию и делать больше.
6. Как создать воркера
очень простой
// 应用文件 app.js
var worker = new Worker('./my.worker.js'); // 传入 worker 脚本文件的路径即可
7. Как общаться с работниками
Это можно сделать двумя способами:
Файл приложения app.js
// 创建 worker 实例
var worker = new Worker('./my.worker.js'); // 传入 worker 脚本文件的路径即可
// 监听消息
worker.onmessage = function(evt){
// 主线程收到工作线程的消息
};
// 主线程向工作线程发送消息
worker.postMessage({
value: '主线程向工作线程发送消息'
});
рабочий файл my.worker.js
// 监听消息
this.onmessage = function(evt){
// 工作线程收到主线程的消息
};
this.postMessage({
value: '工作线程向主线程发送消息'
});
8. Глобальная область действия работника
Самое важное, что нужно знать об использовании Web Worker, это то, что исполняемый им код js находится полностью в другой области видимости и не разделяет область действия с кодом текущего основного потока. В Web Worker также есть глобальный объект и другие объекты и методы, но его код не может получить доступ к DOM и не может повлиять на внешний вид страницы.
Глобальным объектом в Web Worker является сам объект worker, т.е.this
а такжеself
Все ссылки являются рабочими объектами, грубо говоря, как и предыдущий абзац вmy.worker.js
код,this
полностью заменяемыйself
, можно даже опустить.
Для облегчения обработки данных сам Web Worker представляет собой минимальную среду выполнения, которая может получать доступ к следующим данным или использовать их:
- Минимизировать
navigator
объект включатьonLine
,appName
,appVersion
,userAgent
а такжеplatform
Атрибуты - только чтение
location
объект -
setTimeout()
,setInterval()
,clearTimeout()
,clearInterval()
метод -
XMLHttpRequest
Конструктор
9. Как завершить рабочий поток
Если вы не хотите, чтобы Worker продолжал работать в определенное время, то нам нужно завершить поток, вы можете вызвать Worker в основном потокеterminate
метод или вызов в соответствующем потокеclose
метод:
Файл приложения app.js
var worker = new Worker('./worker.js');
// ...一些操作
worker.terminate();
Рабочий файл my.worker.js
self.close();
10. Механизм обработки ошибок воркера
В частности, пока js внутри Worker сталкивается с ошибкой во время выполнения, он вызываетerror
мероприятие. происходитьerror
Когда происходит событие, объект события содержит три свойства:filename
, lineno
а такжеmessage
, которые представляют имя файла, в котором произошла ошибка, номер строки и полное сообщение об ошибке соответственно.
worker.addEventListener('error', function (e) {
console.log('MAIN: ', 'ERROR', e);
console.log('filename:' + e.filename + '-message:' + e.message + '-lineno:' + e.lineno);
});
11. Импорт скриптов и библиотек
Рабочие потоки могут получить доступ к глобальной функцииimportScripts()
Для импорта скриптов эта функция принимает ноль или более URI в качестве параметров для импорта ресурсов; допустимы все следующие примеры:
importScripts(); /* 什么都不引入 */
importScripts('foo.js'); /* 只引入 "foo.js" */
importScripts('foo.js', 'bar.js'); /* 引入两个脚本 */
Браузер загружает и запускает каждый из перечисленных сценариев. Глобальный объект в каждом скрипте может использоваться рабочими. Выдает, если скрипт не может быть загруженNETWORK_ERROR
Исключение, следующий код не может быть выполнен. в то время как ранее выполненный код (в том числе с использованиемwindow.setTimeout()
Асинхронно исполняемый код) по-прежнему сможет выполняться.importScripts()
Последующие объявления функций по-прежнему сохраняются, поскольку они всегда выполняются перед другим кодом.
Примечание: Порядок загрузки скрипта не фиксирован, но он будет выполняться в соответствии с поступающим
importScripts()
в порядке имен файлов. Этот процесс выполняется синхронно, пока все скрипты не будут загружены и запущены,importScripts()
вернусь.
Приложение: Ссылки по теме
URL-адрес рабочего-загрузчика на github:GitHub.com/Webpack-con…
китайская документация webpack (сообщество):doc.Web pack-China.org/loaders/ Я делаю…
китайская документация webpack (сторонняя сторона):Woohoo. CSS88.com/doc/Web pack…
Область проблемы в HMR в режиме devServer: «Webpack 4.0.1 | WebWorkerwindow is not defined
》GitHub.com/Webpack/Веб…
Тематическая область, которая полностью решает вышеперечисленные проблемы: «Добавитьtarget: "universal"
》GitHub.com/Webpack/Веб…