Worker를 사용하여 React에서 성능 최적화하기

MNIII
5 min readSep 26, 2023

--

JavaScript는 싱글 스레드 언어로, 한 번에 하나의 작업만 처리할 수 있다. 이러한 특성은 복잡하고 연산이 많은 작업을 수행할 때 애플리케이션의 성능에 부담을 줄 수 있다. Worker는 이러한 문제를 해결한 방법중 하나로 실제 활용 방법과 React 애플리케이션에서 Worker를 효과적으로 사용하는 방법을 알아보자.

Web Worker

Worker는 메인 스레드와 독립적으로 실행되는 별도의 스레드에서 코드를 실행 한다. 이를 통해 메인 스레드는 UI와 상호작용에 집중하고, 백그라운드에서는 복잡한 연산이나 데이터 처리 작업을 수행할 수 있게 된다.

이러한 방식은 특히 연산이 복잡하고 시간이 많이 소요되는 작업을 처리할 때 유용하며, 사용자 경험을 크게 향상시킬 수 있다.

// main.js
const worker = new Worker('worker.js');

worker.onmessage = function(e) { // Waiting for reception from the worker thread
const processedResult = e.data;
console.log('Processed Result from Worker Thread:', processedResult);
};

const dataToSend = 1;

worker.postMessage(dataToSend);
// worker.js
onmessage = function(e) { // Waiting for reception from the main thread
const receivedData = e.data;
const processedData = () => receivedData * 100;

postMessage(processedData());
};

React에서 Worker 사용 방법

Worker를 React에서 적절하게 활용하면, 복잡한 작업을 하더라도 사용자 인터페이스가 더욱 자연스럽게 반응한다. Worker를 React에서 효과적으로 활용하기 위해 커스텀 훅을 활용해 보자.

// app.tsx
import useWorker from "./useWorker.ts";

const App = () => {
const [result, postMessage] = useWorker({ url: "src/worker.ts" });

return (
<>
<h1>Result from Worker: {result}</h1>
<button onClick={() => postMessage("worker data")}>send</button>
</>
);
};
// useWorker.ts
import { useEffect, useState, useRef, useCallback } from "react";

type UseWorkerResult = [
result: string | null,
postMessage: (message: string) => void
];

const useWorker = ({ url }: { url: string }): UseWorkerResult => {
const [result, setResult] = useState(null);
const workerRef = useRef<Worker | null>(null);

useEffect(() => {
workerRef.current = new Worker(url);

workerRef.current.onmessage = (e) => {
setResult(e.data);
};

return () => {
if (workerRef.current) workerRef.current.terminate();
};
}, [url]);

const postMessage = useCallback((message: string) => {
if (workerRef.current) workerRef.current.postMessage(message);
}, []);

return [result, postMessage];
};

export default useWorker;
// worker.ts
onmessage = function (e) {
const processedData = () => {
return "Received " + e.data;
};
postMessage(processedData());
};

활용 가능한 케이스들:

  • 큰 이미지 처리: 큰 이미지의 로딩이나 처리를 백그라운드에서 수행할 수 있고, 이미지를 처리 동안에도 애플리케이션을 자유롭게 사용 할 수 있다.
  • 데이터 분석 및 처리: 복잡한 데이터 분석이나 처리 작업을 Worker에서 수행하면, 메인 스레드의 부하를 줄일 수 있다.
  • 3D 그래픽 렌더링: 3D 그래픽 렌더링과 같은 리소스 집약적인 작업을 백그라운드에서 처리하면, 애플리케이션의 전반적인 성능이 향상 된다.

Worker의 활용은 React 프로젝트에서 성능을 크게 향상시킬 수 있는 방법 중 하나이다. 특히, 리소스를 많이 사용하는 작업을 백그라운드에서 실행 함으로써, 사용자는 더욱 원활하고 반응성 있는 애플리케이션을 경험할 수 있게 된다. 사용자 경험을 향상시키고, 애플리케이션의 성능을 최적화하기 위해 적절한 상황을 고려해서 Worker 를 사용해 보자.

--

--