Hooks
useWorker

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>
  );
};