useWorker
Introduce
웹 워커 (opens in a new tab)를 사용하여 비동기 작업을 처리하는 훅입니다.
비동기 작업을 백그라운드에서 실행하여 UI 스레드의 성능을 향상시킵니다.
interface UseWorkerProps<Arg, Return, Closure = never> {
script: WorkerScript<Arg, Return, Closure>;
}
interface UseWorkerReturns<Return> {
result: Return | undefined;
start: (args: Arg, closure?: Closure) => void;
cancel: () => void;
}
const useWorker = <Arg, Return, Closure = never>(props: UseWorkerProps<Arg, Return, Closure>): UseWorkerReturns<Return>
-
메인 스레드(주 스레드)와는 별도의 스레드에서 자바스크립트 코드를 실행하여 작업을 수행하고, 메인 스레드가 UI 렌더링과 같은 다른 작업을 차질 없이 진행할 수 있도록 도와줍니다.
-
기본적인 작업 외에 네트워크 요청도 워커 스레드 내부에서 동작이 가능하도록 구현하였습니다.
-
컴포넌트가 언마운트될 때, 사용 중이던 웹 워커를 자동으로 정리합니다.
Props
script
- 웹 워커에서 실행할 함수를 전달합니다.
Returns
result
: 작업의 결과를 저장하는 상태 값입니다. 작업이 완료되면 값이 동적으로 업데이트됩니다.start
: 작업을 시작하는 함수입니다. 이 함수를 호출하면 웹 워커가 생성되고 작업이 시작됩니다.cancel
: 현재 진행 중인 작업을 취소하는 함수입니다. 호출 시 활성화된 웹 워커가 종료됩니다.
🚫
useWorker 훅은 브라우저 환경에서만 동작합니다.
Type
Arg
: 작업에 필요한 인수 타입입니다.Return
: 작업 결과의 반환 타입입니다.Closure
:클로저(closure)로 전달될 타입입니다. 전달된 값은 작업 스레드의 추가 인자로 전달됩니다. (선택 사항)
Examples
TestComponent.tsx
const App = () => {
const [count, setCount] = useState(0);
// <SynchronousComponent /> 컴포넌트는 매우 복잡한 계산이 수행될 때,
// 버튼 클릭과 같은 상호작용 이벤트가 처리되지 않는 블로킹 현상이 발생합니다.
// 반면, <WorkerComponent /> 컴포넌트는 웹 워커를 사용해 무거운 작업을 별도의 스레드에서 처리하므로,
// 메인 스레드에서는 버튼 클릭과 같은 이벤트를 원활하게 처리할 수 있습니다.
return (
<div>
<h1>O(n^2) 100억 연산 블로킹 테스트</h1>
<h1>메인 스레드 비블로킹 작업 (Web Worker 사용)</h1>
<WorkerComponent />
<h1>메인 스레드 블로킹 작업 (Web Worker 미사용)</h1>
<SynchronousComponent />
<button
onClick={() =>
setCount((prev) => prev + 1)
}>{`나를 클릭해주세요!: ${count}`}</button>
</div>
);
};
const size = 100_000;
// 테스트용 O(n^2) 작업
const workerScript = (num: number): number => {
let sum = 0;
for (let i = 1; i <= num; i++) {
for (let j = 1; j <= num; j++) {
sum += i * j;
}
}
return sum;
};
const WorkerComponent = () => {
const [input, setInput] = useState(size);
const { result, start, cancel } = useWorker(workerScript);
const handleStart = () => {
start(input);
};
return (
<div>
<input
type="number"
value={input}
disabled
onChange={(e) => setInput(parseInt(e.target.value, 10))}
/>
<button onClick={handleStart}>Start Worker</button>
<button onClick={cancel}>Cancel Worker</button>
<pre>{result ? JSON.stringify(result, null, 2) : 'No result'}</pre>
</div>
);
};
const SynchronousComponent = () => {
const [input, setInput] = useState(size);
const [result, setResult] = useState(0);
const handleStart = () => {
setResult(workerScript(input));
};
return (
<div>
<input
type="number"
value={input}
disabled
onChange={(e) => setInput(parseInt(e.target.value, 10))}
/>
<button onClick={handleStart}>Start Synchronous</button>
<div>Result: {result}</div>
</div>
);
};