React 中的 Web Workers 是允許在 React 應用程式中並發運行多個執行緒的函數。它允許某些執行緒在背景運行,以排除其作為主執行緒的一部分運行。
例如,您有一個應用程序,您可能想要執行複雜的計算、從 API 獲取大數據或實現後台通知,而不改變當前運行的主線程的正常功能。這可以透過實作 React Web Hooks 來實現,確保當所有這些進程在 React 應用程式中運行時使用者介面不會凍結。
在本指南中,我們將建立一個範例 React 項目,該項目在自訂 React hook 中實作 Web Worker 來執行指數計算。
建立一個反應應用程式。
npx create-vite myproject -- --template react
我更喜歡使用 vite 創建 React 應用程序,因為與 create-react-app 相比,它的運行時間更快。
這裡我們使用vite中的react作為模板。
選擇 JavaScript:
在編輯器上開啟項目。 (我將在這個專案中使用 Vs code)
code .
在 src 目錄中,建立另一個目錄 hooks/useWebWorkers。
在此資料夾中,建立一個 index.js 檔案來保存我們的 Web Worker,如下所示:
在 /hooks/useWebWorker/index.js 中,我們建立一個自訂掛鉤,用於建立我們的 Web Worker
建立一個 useWebWorker 自訂鉤子,以workerFunction 和 inputData 作為參數。
const useWebWorker =(workerFunction,inputData)=>{ } export default useWebWorker;
使用 useState 鉤子初始化我們的結果、錯誤和 Web Worker 狀態的狀態。
import {useState} from 'react' const useWebWorker =(workerFunction,inputData)=>{ const [result,setResult] = useState(null); const [error,setError] = useState(null); const [loading,setLoading] = useState(false); } export default useWebWorker;
i) result 儲存我們網路工作者的結果。初始設定為 null。
ii)error 追蹤 Web Worker 中可能發生的錯誤。最初設定為 null。
iii) 載入給出了我們的 Web Worker 的狀態,無論它是否正在處理資料。最初設定為 false。
初始化 useEffect 來保存我們的 Web Worker。
import {useState,useEffect} from 'react' const useWebWorker =(workerFunction,inputData)=>{ const [result,setResult] = useState(null); const [error,setError] = useState(null); const [loading,setLoading] = useState(false); useEffect(()=>{ },[inputData]) } export default useWebWorker;
只要 inputData 發生變化,useEffect 鉤子就會運行,因為它已被設定為分隔符,
當 inputData 為 null 或未定義時,鉤子提前退出。
if(!inputData)return;
確保所有狀態都正確重置
setLoading(true); setError(null); setResult(null);
const blob = new Blob( [ ` self.onmessage = function(event) { (${workerFunction.toString()})(event); }; `, ], { type: "application/javascript" } );
將workerFunction 轉換為字串並包含在Blob 物件中。此Blob 表示將在Web Worker 中執行的JavaScript 程式碼。
建立一個為 Blob 產生 URL 的 Worker,並使用此 URL 建立一個新的 Web Worker:
const workerScriptUrl = URL.createObjectURL(blob); const worker = new Worker(workerScriptUrl);
為工作人員發出的訊息設定事件處理程序。
worker.onmessage(event){ }
當 Web Worker 向主執行緒傳送訊息(使用 postMessage)時,會觸發事件處理程序。
event.data 包含 Web Worker 中的有效結果或錯誤。我們處理 if-else 語句中錯誤或有效結果的呈現。
如果發生錯誤,我們將錯誤設為 setError() 內的 event.data.error。
如果傳回有效結果,我們將結果傳遞給 setResult()
內的 event.data
worker.onmessage = (event) => { console.log("Worker result:", event.data); if (event.data.error) { setError(event.data.error); } else { setResult(event.data); } setLoading(false); };
完成後將載入設定為 false。
我們用worker.onerror(event){
}
我們將 event 作為參數傳遞,將錯誤更新為 event.message 並將載入狀態更新為 false。
worker.onerror = (event) => { console.error("Worker error:", event.message); setError(event.message); setLoading(false); };
我們現在將 inputData 傳送給網路工作者
worker.postMessage(inputData);
當元件卸載或 inputData 或workerFunction 變更時,我們終止 Web Worker 並撤銷 Blob URL:
return () => { worker.terminate(); URL.revokeObjectURL(workerScriptUrl); }; }, [inputData, workerFunction]);
我們最終透過傳回結果、錯誤和載入狀態來傳回 Web Worker 的狀態:
return {result,error,loading}
匯出 useWebWorker:
export default useWebWorker;
以下是hooks/useWebWorker/index.js的完整程式碼:
import { useState, useEffect } from "react"; const useWebWorker = (workerFunction, inputData) => { const [result, setResult] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); useEffect(() => { if (!inputData) return; setLoading(true); setError(null); setResult(null); const blob = new Blob( [ ` self.onmessage = function(event) { (${workerFunction})(event); }; `, ], { type: "application/javascript" } ); const workerScriptUrl = URL.createObjectURL(blob); const worker = new Worker(workerScriptUrl); worker.onmessage = (event) => { console.log("Worker result:", event.data); setResult(event.data); setLoading(false); }; worker.onerror = (event) => { console.error("Worker error:", event.message); setError(event.message); setLoading(false); }; console.log("Posting message to worker:", inputData); worker.postMessage(inputData); return () => { worker.terminate(); URL.revokeObjectURL(workerScriptUrl); }; }, [inputData, workerFunction]); return { result, error, loading }; }; export default useWebWorker;
在我們的 App.jsx 中,我們定義一個將由我們的 Web Worker 執行的工作函數:
const workerFunction = (e) => { const { base, exponent } = e.data; console.log("Worker function received data:", base, exponent); let result = 1; for (let i = 0; i < exponent; i++) { result *= base; } self.postMessage(result); };
e.data contains data from the web worker.
The workerFunction:
Logs the received data (base and exponent).
Computes the power of base raised to exponent.
Sends the result back to the main thread using self.postMessage(result).
Let's now define our App functional component inside our App.jsx:
const App = () => { const [base, setBase] = useState(""); const [exponent, setExponent] = useState(""); const [inputData, setInputData] = useState(null); const { result, error, loading } = useWebWorker(workerFunction, inputData);
base: Stores the base number input.
exponent: Stores the exponent number input.
inputData: Stores the data to be sent to the worker.
Custom Hook Usage: useWebWorker is used to create a Web Worker and manage its state.
const handleBaseChange = (e) => setBase(e.target.value); const handleExponentChange = (e) => setExponent(e.target.value);
handleBaseChange: Updates base state when the input value changes.
handleExponentChange: Updates exponent state when the input value changes
const handleCalculate = () => { setInputData({ base: Number(base), exponent: Number(exponent) }); };
handleCalculate Function: Converts base and exponent to numbers and sets them as inputData for the Web Worker.
return ( <div> <h1>Exponential Calculation with Web Worker</h1> <div> <label> Base: <input type="number" value={base} onChange={handleBaseChange} /> </label> </div> <div> <label> Exponent: <input type="number" value={exponent} onChange={handleExponentChange} /> </label> </div> <button onClick={handleCalculate}>Calculate</button> {loading && <div>Loading...</div>} {error && <div>Error: {error}</div>} {!loading && !error && result !== null && <div>Result: {result}</div>} </div> ); };
JSX Layout:
Displays a title and input fields for base and exponent.
A button triggers the handleCalculate function.
Conditionally renders loading, error, or result messages based on the state.
Below is the complete App.jsx code:
import { useState } from "react"; import useWebWorker from "./hooks/useWebWorker"; import "./App.css"; const workerFunction = (e) => { const { base, exponent } = e.data; console.log("Worker function received data:", base, exponent); let result = 1; for (let i = 0; i < exponent; i++) { result *= base; } self.postMessage(result); }; const App = () => { const [base, setBase] = useState(""); const [exponent, setExponent] = useState(""); const [inputData, setInputData] = useState(null); const { result, error, loading } = useWebWorker(workerFunction, inputData); const handleBaseChange = (e) => setBase(e.target.value); const handleExponentChange = (e) => setExponent(e.target.value); const handleCalculate = () => { setInputData({ base: Number(base), exponent: Number(exponent) }); }; return ( <div> <h1>Exponential Calculation with Web Worker</h1> <div> <label> Base: <input type="number" value={base} onChange={handleBaseChange} /> </label> </div> <div> <label> Exponent: <input type="number" value={exponent} onChange={handleExponentChange} /> </label> </div> <button onClick={handleCalculate}>Calculate</button> {loading && <div>Loading...</div>} {error && <div>Error: {error}</div>} {!loading && !error && result !== null && <div>Result: {result}</div>} </div> ); }; export default App;
We can now use npm run dev to view our project.
Below is a live preview of our project:
Web Workers Project Implementation
Implementing Web Workers in your React applications can significantly enhance performance, especially when dealing with CPU-intensive tasks. By offloading such tasks to background threads, you ensure that your app remains responsive and provides a smooth user experience.
In our example, we've seen how straightforward it can be to set up and use Web Workers in a React environment. From dynamically creating a worker using a custom hook to managing the communication between the main thread and the worker, every step is designed to be both efficient and easy to integrate.
This approach not only helps in maintaining a responsive UI but also makes your app more robust and user-friendly. Whether it's for complex calculations, data processing, or any other heavy lifting, Web Workers can be your go-to solution for multitasking in modern web applications.
Remember, the key to a great user experience is not just about what your app does but how it feels while doing it. By implementing Web Workers, you can ensure that your app feels snappy and responsive, keeping your users happy and engaged. So, go ahead and explore the power of Web Workers in your next React project – your users will thank you for it!
以上是在 React Hooks 應用程式中利用 Web Worker 進行背景處理。的詳細內容。更多資訊請關注PHP中文網其他相關文章!