Управление длительными задачами в приложении React с помощью Web Workers

Опубликовано: 2022-03-10
Краткое резюме ↬ В этом руководстве мы узнаем, как использовать API Web Worker для управления трудоемкими и блокирующими пользовательский интерфейс задачами в приложении JavaScript, создав образец веб-приложения, использующего Web Workers. Наконец, мы закончим статью переносом всего в приложение React.

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

При написании этой статьи я исходил из следующих предположений:

  1. Чтобы иметь возможность следовать, вы должны иметь хотя бы некоторое представление о JavaScript и API документов;
  2. У вас также должны быть практические знания React, чтобы вы могли успешно запустить новый проект React с помощью Create React App.

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

Во-первых, давайте начнем с Web Workers.

Что такое веб-воркер?

Чтобы понять Web Workers и проблему, которую они призваны решать, необходимо понять, как выполняется код JavaScript во время выполнения. Во время выполнения код JavaScript выполняется последовательно и пошагово. Как только часть кода заканчивается, начинает работать следующая в очереди и так далее. С технической точки зрения мы говорим, что JavaScript является однопоточным. Такое поведение подразумевает, что как только какой-то фрагмент кода начинает выполняться, каждый последующий код должен ждать завершения выполнения этого кода. Таким образом, каждая строка кода «блокирует» выполнение всего остального, что следует за ней. Поэтому желательно, чтобы каждый фрагмент кода завершался как можно быстрее. Если выполнение какого-то фрагмента кода занимает слишком много времени, наша программа будет казаться остановленной. В браузере это проявляется как зависшая и не отвечающая страница. В некоторых крайних случаях вкладка вообще зависнет.

Представьте, что вы едете по однополосной дороге. Если кто-то из водителей впереди вас по какой-либо причине остановился, значит, у вас пробка. С такой программой, как Java, трафик может продолжаться по другим полосам. Таким образом, говорят, что Java является многопоточным. Web Workers — это попытка реализовать многопоточное поведение в JavaScript.

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

Отображение диаграммы поддержки браузера для веб-воркеров
Поддержка браузера Web Workers. (Большой превью)

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

Отличное определение Web Worker взято из MDN:

«Рабочий процесс — это объект, созданный с помощью конструктора (например, Worker() , который запускает именованный файл JavaScript — этот файл содержит код, который будет выполняться в рабочем потоке; рабочие процессы выполняются в другом глобальном контексте, отличном от текущего window . Таким образом, , используя ярлык window , чтобы получить текущую глобальную область видимости (вместо self в Worker вернет ошибку».

Рабочий процесс создается с помощью конструктора Worker .

 const worker = new Worker('worker-file.js')

Внутри веб-воркеров можно запустить большую часть кода, за некоторыми исключениями. Например, вы не можете манипулировать DOM изнутри рабочего процесса. Нет доступа к API document .

Воркеры и поток, который их порождает, отправляют сообщения друг другу, используя метод postMessage() . Точно так же они отвечают на сообщения, используя обработчик события onmessage . Важно получить эту разницу. Отправка сообщений осуществляется с помощью метода; для получения обратного сообщения требуется обработчик событий. Полученное сообщение содержится в атрибуте data события. Мы увидим пример этого в следующем разделе. Но позвольте мне быстро упомянуть, что тип работника, которого мы обсуждали, называется «преданным работником». Это означает, что рабочий процесс доступен только тому сценарию, который его вызвал. Также возможно иметь рабочего, доступного из нескольких сценариев. Они называются общими рабочими процессами и создаются с помощью конструктора SharedWorker , как показано ниже.

 const sWorker = new SharedWorker('shared-worker-file.js')

Чтобы узнать больше о Workers, ознакомьтесь с этой статьей MDN. Цель этой статьи — помочь вам начать работу с веб-воркерами. Давайте перейдем к этому, вычислив n-е число Фибоначчи.

Еще после прыжка! Продолжить чтение ниже ↓

Вычисление N-го числа Фибоначчи

Примечание. В этом и следующих двух разделах я использую Live Server на VSCode для запуска приложения. Вы, конечно, можете использовать что-то еще.

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

Представьте, что вы создаете веб-приложение, позволяющее пользователям вычислять n-е число Фибоначчи. Если вы не знакомы с термином «число Фибоначчи», вы можете прочитать о нем больше здесь, но в целом числа Фибоначчи — это последовательность чисел, в которой каждое число является суммой двух предыдущих чисел.

Математически это выражается как:

Таким образом, первые несколько чисел последовательности:

1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ...

В некоторых источниках последовательность начинается с F 0 = 0 , и в этом случае приведенная ниже формула выполняется для n > 1 :

В этой статье мы начнем с F 1 = 1. Из формулы сразу видно, что числа следуют рекурсивному образцу. Теперь наша задача состоит в том, чтобы написать рекурсивную функцию для вычисления n-го числа Фибоначчи (FN).

После нескольких попыток, я думаю, вы легко сможете придумать функцию, описанную ниже.

 const fib = n => { if (n < 2) { return n // or 1 } else { return fib(n - 1) + fib(n - 2) } }

Функция проста. Если n меньше 2, вернуть n (или 1), в противном случае вернуть сумму n-1 и n-2 FN. Со стрелочными функциями и тернарным оператором мы можем придумать однострочник.

 const fib = n => (n < 2 ? n : fib(n-1) + fib(n-2))

Эта функция имеет временную сложность 0(2 n ) . Это просто означает, что по мере увеличения значения n время, необходимое для вычисления суммы, увеличивается экспоненциально. Это создает действительно длительную задачу, которая потенциально может мешать нашему пользовательскому интерфейсу при больших значениях n. Давайте посмотрим на это в действии.

Примечание : это ни в коем случае не лучший способ решить эту конкретную проблему. Я выбрал этот метод для целей этой статьи.

Для начала создайте новую папку и назовите ее как хотите. Теперь внутри этой папки создайте папку src/ . Также создайте файл index.html в корневой папке. Внутри папки src/ создайте файл с именем index.js .

Откройте index.html и добавьте следующий код HTML.

 <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="styles.css"> </head> <body> <div class="heading-container"> <h1>Computing the nth Fibonnaci number</h1> </div> <div class="body-container"> <p id='error' class="error"></p> <div class="input-div"> <input id='number-input' class="number-input" type='number' placeholder="Enter a number" /> <button id='submit-btn' class="btn-submit">Calculate</button> </div> <div id='results-container' class="results"></div> </div> <script src="/src/index.js"></script> </body> </html>

Эта часть очень проста. Во-первых, у нас есть заголовок. Затем у нас есть контейнер с полем ввода и кнопкой. Пользователь вводит число и нажимает «Рассчитать». У нас также есть контейнер для хранения результата расчета. Наконец, мы включаем файл src/index.js в тег script .

Вы можете удалить ссылку на таблицу стилей. Но если у вас мало времени, я определил CSS, который вы можете использовать. Просто создайте файл styles.css в корневой папке и добавьте стили ниже:

 body { margin: 0; padding: 0; box-sizing: border-box; } .body-container, .heading-container { padding: 0 20px; } .heading-container { padding: 20px; color: white; background: #7a84dd; } .heading-container > h1 { margin: 0; } .body-container { width: 50% } .input-div { margin-top: 15px; margin-bottom: 15px; display: flex; align-items: center; } .results { width: 50vw; } .results>p { font-size: 24px; } .result-div { padding: 5px 10px; border-radius: 5px; margin: 10px 0; background-color: #e09bb7; } .result-div p { margin: 5px; } span.bold { font-weight: bold; } input { font-size: 25px; } p.error { color: red; } .number-input { padding: 7.5px 10px; } .btn-submit { padding: 10px; border-radius: 5px; border: none; background: #07f; font-size: 24px; color: white; cursor: pointer; margin: 0 10px; }

Теперь откройте src/index.js , давайте медленно его разработаем. Добавьте код ниже.

 const fib = (n) => (n < 2 ? n : fib(n - 1) + fib(n - 2)); const ordinal_suffix = (num) => { // 1st, 2nd, 3rd, 4th, etc. const j = num % 10; const k = num % 100; switch (true) { case j === 1 && k !== 11: return num + "st"; case j === 2 && k !== 12: return num + "nd"; case j === 3 && k !== 13: return num + "rd"; default: return num + "th"; } }; const textCont = (n, fibNum, time) => { const nth = ordinal_suffix(n); return ` <p id='timer'>Time: <span class='bold'>${time} ms</span></p> <p><span class="bold" id='nth'>${nth}</span> fibonnaci number: <span class="bold" id='sum'>${fibNum}</span></p> `; };

Здесь у нас есть три функции. Первая — это функция, которую мы видели ранее для вычисления n-го FN. Вторая функция — это просто служебная функция для присоединения соответствующего суффикса к целому числу. Третья функция принимает некоторые аргументы и выводит разметку, которую мы позже вставим в DOM. Первый аргумент — это число, для которого вычисляется FN. Второй аргумент — вычисленный FN. Последний аргумент — это время, необходимое для выполнения вычисления.

По-прежнему в src/index.js добавьте приведенный ниже код прямо под предыдущим.

 const errPar = document.getElementById("error"); const btn = document.getElementById("submit-btn"); const input = document.getElementById("number-input"); const resultsContainer = document.getElementById("results-container"); btn.addEventListener("click", (e) => { errPar.textContent = ''; const num = window.Number(input.value); if (num < 2) { errPar.textContent = "Please enter a number greater than 2"; return; } const startTime = new Date().getTime(); const sum = fib(num); const time = new Date().getTime() - startTime; const resultDiv = document.createElement("div"); resultDiv.innerHTML = textCont(num, sum, time); resultDiv.className = "result-div"; resultsContainer.appendChild(resultDiv); });

Во-первых, мы используем API document , чтобы получить узлы DOM в нашем файле HTML. Получаем ссылку на абзац, где будем выводить сообщения об ошибках; вход; кнопку расчета и контейнер, в котором мы покажем наши результаты.

Далее мы прикрепляем к кнопке обработчик события click. Когда кнопка нажата, мы берем все, что находится внутри элемента ввода, и преобразуем его в число, если мы получаем что-то меньше 2, мы отображаем сообщение об ошибке и возвращаемся. Если мы получаем число больше 2, мы продолжаем. Во-первых, мы записываем текущее время. После этого вычисляем ФН. Когда это закончится, мы получим разницу во времени, которая показывает, сколько времени заняло вычисление. В оставшейся части кода мы создаем новый div . Затем мы устанавливаем его внутренний HTML как вывод функции textCont() , которую мы определили ранее. Наконец, мы добавляем к нему класс (для стилизации) и присоединяем его к контейнеру результатов. Результатом этого является то, что каждое вычисление будет отображаться в отдельном div ниже предыдущего.

Отображение вычисленных чисел Фибоначчи до 43
Некоторые числа Фибоначчи. (Большой превью)

Мы видим, что по мере увеличения числа время вычисления также увеличивается (экспоненциально). Например, с 30 до 35 у нас был скачок времени вычислений с 13 мс до 130 мс. Мы по-прежнему можем считать эти операции «быстрыми». В 40 мы видим время вычисления более 1 секунды. На моей машине именно здесь я начинаю замечать, что страница перестает отвечать на запросы. На данный момент я больше не могу взаимодействовать со страницей, пока выполняются вычисления. Я не могу сосредоточиться на вводе или сделать что-нибудь еще.

Помните, мы говорили об однопоточности JavaScript? Что ж, этот поток был «заблокирован» этим длительным вычислением, поэтому все остальное должно «ждать» его завершения. Он может начинаться с более низкого или более высокого значения на вашем компьютере, но вы обязательно достигнете этой точки. Обратите внимание, что для вычисления 44 потребовалось почти 10 секунд. Если бы в вашем веб-приложении были другие действия, пользователь должен был бы дождаться завершения Fib(44), прежде чем он сможет продолжить. Но если вы развернули веб-воркер для обработки этих вычислений, ваши пользователи могли бы заниматься чем-то еще, пока он выполняется.

Давайте теперь посмотрим, как веб-воркеры помогают нам решить эту проблему.

Пример веб-воркера в действии

В этом разделе мы делегируем работу по вычислению n-го FN веб-воркеру. Это поможет освободить основной поток и сохранить отзывчивость нашего пользовательского интерфейса во время выполнения вычислений.

Начать работу с веб-воркерами на удивление просто. Посмотрим, как. Создайте новый файл src/fib-worker.js . и введите следующий код.

 const fib = (n) => (n < 2 ? n : fib(n - 1) + fib(n - 2)); onmessage = (e) => { const { num } = e.data; const startTime = new Date().getTime(); const fibNum = fib(num); postMessage({ fibNum, time: new Date().getTime() - startTime, }); };

Обратите внимание, что мы переместили функцию, вычисляющую n-е число Фибоначчи, fib внутрь этого файла. Этот файл будет запускаться нашим веб-воркером.

Напомним, в разделе Что такое веб-воркер мы упоминали, что веб-воркеры и их родитель взаимодействуют с помощью обработчика событий onmessage и метода postMessage() . Здесь мы используем обработчик события onmessage для прослушивания сообщений из родительского скрипта. Как только мы получаем сообщение, мы деструктурируем число из атрибута данных события. Далее получаем текущее время и запускаем вычисления. Когда результат готов, мы используем метод postMessage() для отправки результатов обратно в родительский скрипт.

Откройте src/index.js , давайте внесем некоторые изменения.

 ... const worker = new window.Worker("src/fib-worker.js"); btn.addEventListener("click", (e) => { errPar.textContent = ""; const num = window.Number(input.value); if (num < 2) { errPar.textContent = "Please enter a number greater than 2"; return; } worker.postMessage({ num }); worker.onerror = (err) => err; worker.onmessage = (e) => { const { time, fibNum } = e.data; const resultDiv = document.createElement("div"); resultDiv.innerHTML = textCont(num, fibNum, time); resultDiv.className = "result-div"; resultsContainer.appendChild(resultDiv); }; });

Первое, что нужно сделать, это создать веб-воркер с помощью конструктора Worker . Затем внутри прослушивателя событий нашей кнопки мы отправляем число рабочему процессу, используя worker.postMessage({ num }) . После этого устанавливаем функцию прослушивания ошибок в воркере. Здесь мы просто возвращаем ошибку. Вы, конечно, можете сделать больше, если хотите, например, показать это в DOM. Далее мы прослушиваем сообщения от воркера. Как только мы получим сообщение, мы деструктурируем time и fibNum и продолжим процесс их отображения в DOM.

Обратите внимание, что внутри веб- onmessage событие onmessage доступно в области действия работника, поэтому мы могли бы записать его как self.onmessage и self.postMessage() . Но в родительском скрипте мы должны прикрепить их к самому рабочему процессу.

На снимке экрана ниже вы увидите файл веб-воркера на вкладке «Источники» Chrome Dev Tools. Что вы должны заметить, так это то, что пользовательский интерфейс остается отзывчивым независимо от того, какое число вы вводите. Такое поведение — магия веб-воркеров.

Просмотр активного файла веб-воркера
Работающий файл веб-воркера. (Большой превью)

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

Работа с несколькими веб-воркерами

В настоящее время мы обрабатываем каждый запрос одним работником. Таким образом, входящий запрос заменит предыдущий, который еще не завершен. Сейчас мы хотим внести небольшое изменение, чтобы создавать новый веб-воркер для каждого запроса. Мы убьем этого работника, как только это будет сделано.

Откройте src/index.js и переместите строку, создающую веб-воркер, внутрь обработчика события нажатия кнопки. Теперь обработчик события должен выглядеть так, как показано ниже.

 btn.addEventListener("click", (e) => { errPar.textContent = ""; const num = window.Number(input.value); if (num < 2) { errPar.textContent = "Please enter a number greater than 2"; return; } const worker = new window.Worker("src/fib-worker.js"); // this line has moved inside the event handler worker.postMessage({ num }); worker.onerror = (err) => err; worker.onmessage = (e) => { const { time, fibNum } = e.data; const resultDiv = document.createElement("div"); resultDiv.innerHTML = textCont(num, fibNum, time); resultDiv.className = "result-div"; resultsContainer.appendChild(resultDiv); worker.terminate() // this line terminates the worker }; });

Мы внесли два изменения.

  1. Мы переместили эту строку const worker = new window.Worker("src/fib-worker.js") внутрь обработчика события нажатия кнопки.
  2. Мы добавили эту строку worker.terminate() , чтобы отбросить работника, как только мы закончим с ним.

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

показ чисел Фибоначчи с уволенными рабочими
Иллюстрация нескольких независимых работников. (Большой превью)

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

Веб-воркеры в реакции

Для начала создайте новое приложение для реагирования с помощью CRA. Скопируйте файл fib-worker.js в папку public/ вашего приложения для реагирования. Размещение файла здесь связано с тем, что приложения React являются одностраничными приложениями. Это единственное, что характерно для использования работника в реагирующем приложении. Все, что отсюда следует, — это чистый React.

В папке src/ создайте файл helpers.js и экспортируйте из него функцию ordinal_suffix() .

 // src/helpers.js export const ordinal_suffix = (num) => { // 1st, 2nd, 3rd, 4th, etc. const j = num % 10; const k = num % 100; switch (true) { case j === 1 && k !== 11: return num + "st"; case j === 2 && k !== 12: return num + "nd"; case j === 3 && k !== 13: return num + "rd"; default: return num + "th"; } };

Наше приложение потребует от нас поддерживать некоторое состояние, поэтому создайте еще один файл, src/reducer.js и вставьте в него редуктор состояния.

 // src/reducers.js export const reducer = (state = {}, action) => { switch (action.type) { case "SET_ERROR": return { ...state, err: action.err }; case "SET_NUMBER": return { ...state, num: action.num }; case "SET_FIBO": return { ...state, computedFibs: [ ...state.computedFibs, { id: action.id, nth: action.nth, loading: action.loading }, ], }; case "UPDATE_FIBO": { const curr = state.computedFibs.filter((c) => c.id === action.id)[0]; const idx = state.computedFibs.indexOf(curr); curr.loading = false; curr.time = action.time; curr.fibNum = action.fibNum; state.computedFibs[idx] = curr; return { ...state }; } default: return state; } };

Давайте рассмотрим каждый тип действия один за другим.

  1. SET_ERROR : устанавливает состояние ошибки при срабатывании.
  2. SET_NUMBER : устанавливает значение в нашем поле ввода в состояние.
  3. SET_FIBO : добавляет новую запись в массив вычисленных FN.
  4. UPDATE_FIBO : здесь мы ищем определенную запись и заменяем ее новым объектом, который имеет вычисленный FN и время, затраченное на его вычисление.

Мы будем использовать этот редуктор в ближайшее время. Перед этим создадим компонент, который будет отображать вычисленные FN. Создайте новый файл src/Results.js и вставьте в него приведенный ниже код.

 // src/Results.js import React from "react"; export const Results = (props) => { const { results } = props; return ( <div className="results-container"> {results.map((fb) => { const { id, nth, time, fibNum, loading } = fb; return ( <div key={id} className="result-div"> {loading ? ( <p> Calculating the{" "} <span className="bold"> {nth} </span>{" "} Fibonacci number... </p> ) : ( <> <p> Time: <span className="bold">{time} ms</span> </p> <p> <span className="bold"> {nth} </span>{" "} fibonnaci number:{" "} <span className="bold"> {fibNum} </span> </p> </> )} </div> ); })} </div> ); };

С этим изменением мы начинаем процесс преобразования нашего предыдущего файла index.html в jsx. У этого файла есть одна обязанность: взять массив объектов, представляющих вычисленные БС, и отобразить их. Единственное отличие от того, что у нас было раньше, это введение состояния загрузки . Итак, теперь, когда вычисления выполняются, мы показываем состояние загрузки, чтобы пользователь знал, что что-то происходит.

Давайте добавим последние части, обновив код внутри src/App.js . Код довольно длинный, поэтому мы сделаем это в два шага. Добавим первый блок кода.

 import React from "react"; import "./App.css"; import { ordinal_suffix } from "./helpers"; import { reducer } from './reducer' import { Results } from "./Results"; function App() { const [info, dispatch] = React.useReducer(reducer, { err: "", num: "", computedFibs: [], }); const runWorker = (num, id) => { dispatch({ type: "SET_ERROR", err: "" }); const worker = new window.Worker('./fib-worker.js') worker.postMessage({ num }); worker.onerror = (err) => err; worker.onmessage = (e) => { const { time, fibNum } = e.data; dispatch({ type: "UPDATE_FIBO", id, time, fibNum, }); worker.terminate(); }; }; return ( <div> <div className="heading-container"> <h1>Computing the nth Fibonnaci number</h1> </div> <div className="body-container"> <p className="error"> {info.err} </p> // ... next block of code goes here ... // <Results results={info.computedFibs} /> </div> </div> ); } export default App;

Как обычно, мы ввозим наш импорт. Затем мы создаем экземпляр состояния и функции обновления с помощью хука useReducer. Затем мы определяем функцию runWorker() , которая принимает число и идентификатор и приступает к вызову веб-работника для вычисления FN для этого числа.

Обратите внимание, что для создания рабочего процесса мы передаем относительный путь конструктору рабочего процесса. Во время выполнения наш код React прикрепляется к файлу public/index.html , поэтому он может найти файл fib-worker.js в том же каталоге. Когда вычисление завершается (инициируется worker.onmessage ), отправляется действие UPDATE_FIBO , после чего рабочий процесс завершается. То, что мы имеем сейчас, мало чем отличается от того, что было раньше.

В блоке возврата этого компонента мы визуализируем тот же HTML, что и раньше. Мы также передаем вычисленный массив чисел компоненту <Results /> для рендеринга.

Давайте добавим последний блок кода внутрь оператора return .

 <div className="input-div"> <input type="number" value={info.num} className="number-input" placeholder="Enter a number" onChange={(e) => dispatch({ type: "SET_NUMBER", num: window.Number(e.target.value), }) } /> <button className="btn-submit" onClick={() => { if (info.num < 2) { dispatch({ type: "SET_ERROR", err: "Please enter a number greater than 2", }); return; } const id = info.computedFibs.length; dispatch({ type: "SET_FIBO", id, loading: true, nth: ordinal_suffix(info.num), }); runWorker(info.num, id); }} > Calculate </button> </div>

Мы устанавливаем обработчик onChange на входе для обновления переменной состояния info.num . На кнопке мы определяем обработчик события onClick . Когда кнопка нажата, мы проверяем, больше ли число 2. Обратите внимание, что перед вызовом runWorker() мы сначала отправляем действие для добавления записи в массив вычисленных FN. Именно эта запись будет обновлена ​​после того, как рабочий завершит свою работу. Таким образом, каждая запись сохраняет свою позицию в списке, в отличие от того, что было раньше.

Наконец, скопируйте содержимое styles.css и замените содержимое App.css .

Теперь у нас все на месте. Теперь запустите свой реагирующий сервер и поэкспериментируйте с некоторыми числами. Обратите внимание на состояние загрузки, которое является улучшением UX. Также обратите внимание, что пользовательский интерфейс остается отзывчивым, даже когда вы вводите число до 1000 и нажимаете «Рассчитать».

отображение состояния загрузки, пока рабочий активен.
Отображение состояния загрузки и активного веб-воркера. (Большой превью)

Обратите внимание на состояние загрузки и активного работника. После вычисления 46-го значения рабочий процесс уничтожается, а состояние загрузки заменяется окончательным результатом.

  • Исходный код этого приложения React доступен на Github, а на vercel есть размещенное приложение.

Заключение

Фу! Это был долгий путь, так что давайте завершим его. Я рекомендую вам взглянуть на запись MDN для веб-воркеров (см. список ресурсов ниже), чтобы узнать о других способах использования веб-воркеров.

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

Я призываю вас воспользоваться преимуществами этого замечательного API, чтобы предоставить вашим пользователям лучший опыт.

Дополнительные ресурсы

  • Console.time() , веб-документы MDN
  • {JSON} Заполнитель, официальный сайт
  • Использование Web Workers, веб-документов MDN
  • Число Фибоначчи, Википедия
  • Условный (тернарный) оператор, веб-документы MDN
  • Document , веб-API, веб-документы MDN
  • Начало работы, создание приложения React (документы)
  • Function.prototype.toString() , веб-документы MDN
  • IIFE, веб-документы MDN
  • workerSetup.js , Удивительные руководства по Fullstack, GitHub
  • «Параллельное программирование на JavaScript с использованием веб-воркеров», Удай Хиварале, Medium