ReactJs 성능 ~ Web Workers를 이용한 무거운 연산 ~
Source: Dev.to

웹 워커가 유용한 경우
- 브라우저에서 이미지나 비디오 처리
- 대용량 데이터셋(정렬, 필터링, 변환) 처리
- CPU‑집약적인 계산 수행(예: 시뮬레이션, 분석)
- CSV, JSON, XML과 같은 대용량 파일 파싱
- 암호화 또는 해시 연산 실행
- UI를 차단하지 않고 실시간 데이터 스트림 관리
Web Worker 구현 예시
dataWorker.js
// dataWorker.js
self.addEventListener('message', event => {
const { items, taskType } = event.data;
const output = runBackgroundTask(items, taskType);
self.postMessage({
status: 'completed',
result: output,
});
});
function runBackgroundTask(items, taskType) {
if (taskType !== 'transform') {
return items;
}
return items.map(item => {
return applyHeavyTransformation(item);
});
}
function applyHeavyTransformation(item) {
// Put CPU‑heavy logic here
return {
...item,
processed: true,
};
}
DataProcessor.jsx
// DataProcessor.jsx
import { useEffect, useState } from 'react';
function DataProcessor({ items }) {
const [result, setResult] = useState([]);
const [isRunning, setIsRunning] = useState(false);
useEffect(() => {
const backgroundWorker = new Worker(
new URL('./dataWorker.js', import.meta.url)
);
backgroundWorker.addEventListener('message', event => {
setResult(event.data.result);
setIsRunning(false);
});
setIsRunning(true);
backgroundWorker.postMessage({
items,
taskType: 'transform',
});
return () => {
backgroundWorker.terminate();
};
}, [items]);
if (isRunning) {
return ;
}
return ;
}
이 예시에서는 비용이 많이 드는 변환을 메인 React 렌더링 흐름 밖으로 이동합니다. 컴포넌트는 원시 데이터를 워커에 보내고, 처리된 결과를 기다리며, 작업이 백그라운드에서 실행되는 동안 UI가 반응성을 유지합니다.
작업 유형별 성능 비교
| 작업 | 메인 스레드 (≈) | 워커 스레드 (≈) | UI 부드러움 | 구현 난이도 |
|---|---|---|---|---|
| 이미지 필터링 | 800 ms (블록) | 850 ms (오프‑스레드) | 60 FPS 유지 | 보통 |
| 데이터 정렬 (10만 항목) | 450 ms (블로킹) | 480 ms (논블로킹) | 60 FPS 유지 | 낮음 |
| JSON 파싱 (대용량 페이로드) | 600 ms (프리즈) | 620 ms (백그라운드) | 60 FPS 유지 | 낮음 |
| 물리 시뮬레이션 | 1200 ms (프리즈) | 1250 ms (비동기) | 60 FPS 유지 | 높음 |
| 암호화 작업 | 350 ms (블로킹) | 360 ms (반응형) | 60 FPS 유지 | 보통 |
| 비디오 트랜스코딩 | 불가능 (너무 무거움) | 백그라운드에서 실행 | 60 FPS 유지 | 매우 높음 |
Web Workers 사용 전에 알아야 할 사항
- 워커는 DOM과 직접 상호작용할 수 없습니다.
- 메모리는 메인 스레드와 격리되어 있습니다 (SharedArrayBuffer는 고급 우회 방법입니다).
- 스레드 간 통신은 지연을 발생시킵니다 (~5–10 ms per message).
- 스레드 간 데이터를 전달할 때는 직렬화/역직렬화가 필요합니다.
실제로 언제 사용해야 할까요?
좋은 경험법칙: 작업이 ~50 ms 이상 걸린다면 Web Worker의 후보가 됩니다.
짧은 작업의 경우, 메시지 전달 비용이 성능 향상보다 클 수 있습니다. 이런 경우에는 다음을 고려하세요:
requestIdleCallback→ 브라우저가 유휴 상태일 때 작업 실행- 간단한 async 패턴 → 렌더링 차단 방지
Modern tooling makes it easier
- Vite / Webpack → 최소 설정으로 워커를 직접 가져올 수 있게 합니다.
- Comlink → 메시지 전달을 간단한 함수 호출 형태의 API로 추상화합니다.
이 도구들은 보일러플레이트를 줄이고 백그라운드 처리의 통합을 현대 프론트엔드 애플리케이션에 쉽게 합니다.
Practical perspective
Web Workers를 선택적으로 사용하십시오. CPU‑집약적인 시나리오에서는 뛰어나지만, 가벼운 작업의 경우 더 간단한 접근 방식이 전체 성능 및 유지 관리성을 향상시킬 수 있습니다.