|
| 1 | +# useWorker |
| 2 | + |
| 3 | +## Introduce |
| 4 | + |
| 5 | +웹 워커를 사용하여 비동기 작업을 처리하는 훅입니다. |
| 6 | + |
| 7 | +비동기 작업을 백그라운드에서 실행하여 UI 스레드의 성능을 향상시킵니다. |
| 8 | + |
| 9 | +```ts |
| 10 | +interface UseWorkerProps<Arg, Return, Closure = never> { |
| 11 | + script: WorkerScript<Arg, Return, Closure>; |
| 12 | +} |
| 13 | + |
| 14 | +interface UseWorkerReturns<Return> { |
| 15 | + result: Return | undefined; |
| 16 | + start: (args: Arg, closure?: Closure) => void; |
| 17 | + cancel: () => void; |
| 18 | +} |
| 19 | + |
| 20 | +const useWorker = <Arg, Return, Closure = never>(props: UseWorkerProps<Arg, Return, Closure>): UseWorkerReturns<Return> |
| 21 | +``` |
| 22 | +
|
| 23 | +- 메인 스레드(주 스레드)와는 별도의 스레드에서 자바스크립트 코드를 실행하여 작업을 수행하고, |
| 24 | + 메인 스레드가 UI 렌더링과 같은 다른 작업을 차질 없이 진행할 수 있도록 도와줍니다. |
| 25 | +
|
| 26 | +- 기본적인 작업 외에 네트워크 요청도 워커 스레드 내부에서 동작이 가능하도록 구현하였습니다. |
| 27 | +
|
| 28 | +- 컴포넌트가 언마운트될 때, 사용 중이던 웹 워커를 자동으로 정리합니다. |
| 29 | +
|
| 30 | +### Props |
| 31 | +
|
| 32 | +- `script` - 웹 워커에서 실행할 함수를 전달합니다. |
| 33 | +
|
| 34 | +### Returns |
| 35 | +
|
| 36 | +- `result` : 작업의 결과를 저장하는 상태 값입니다. 작업이 완료되면 값이 동적으로 업데이트됩니다. |
| 37 | +- `start` : 작업을 시작하는 함수입니다. 이 함수를 호출하면 웹 워커가 생성되고 작업이 시작됩니다. |
| 38 | +- `cancel` : 현재 진행 중인 작업을 취소하는 함수입니다. 호출 시 활성화된 웹 워커가 종료됩니다. |
| 39 | +
|
| 40 | +import { Callout } from 'nextra/components'; |
| 41 | +
|
| 42 | +<Callout type="error">useWorker 훅은 브라우저 환경에서만 동작합니다.</Callout> |
| 43 | +
|
| 44 | +### Type |
| 45 | +
|
| 46 | +- `Arg` : 작업에 필요한 인수 타입입니다. |
| 47 | +- `Return` : 작업 결과의 반환 타입입니다. |
| 48 | +- `Closure` :클로저(closure)로 전달될 타입입니다. 전달된 값은 작업 스레드의 추가 인자로 전달됩니다. (선택 사항) |
| 49 | +
|
| 50 | +## Examples |
| 51 | +
|
| 52 | +```tsx copy filename="TestComponent.tsx" |
| 53 | +const App = () => { |
| 54 | + const [count, setCount] = useState(0); |
| 55 | + |
| 56 | + // <SynchronousComponent /> 컴포넌트는 매우 복잡한 계산이 수행될 때, |
| 57 | + // 버튼 클릭과 같은 상호작용 이벤트가 처리되지 않는 블로킹 현상이 발생합니다. |
| 58 | + // 반면, <WorkerComponent /> 컴포넌트는 웹 워커를 사용해 무거운 작업을 별도의 스레드에서 처리하므로, |
| 59 | + // 메인 스레드에서는 버튼 클릭과 같은 이벤트를 원활하게 처리할 수 있습니다. |
| 60 | + |
| 61 | + return ( |
| 62 | + <div> |
| 63 | + <h1>O(n^2) 100억 연산 블로킹 테스트</h1> |
| 64 | + <h1>메인 스레드 비블로킹 작업 (Web Worker 사용)</h1> |
| 65 | + <WorkerComponent /> |
| 66 | + <h1>메인 스레드 블로킹 작업 (Web Worker 미사용)</h1> |
| 67 | + <SynchronousComponent /> |
| 68 | + <button |
| 69 | + onClick={() => |
| 70 | + setCount((prev) => prev + 1) |
| 71 | + }>{`나를 클릭해주세요!: ${count}`}</button> |
| 72 | + </div> |
| 73 | + ); |
| 74 | +}; |
| 75 | + |
| 76 | +const size = 100_000; |
| 77 | +// 테스트용 O(n^2) 작업 |
| 78 | +const workerScript = (num: number): number => { |
| 79 | + let sum = 0; |
| 80 | + |
| 81 | + for (let i = 1; i <= num; i++) { |
| 82 | + for (let j = 1; j <= num; j++) { |
| 83 | + sum += i * j; |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + return sum; |
| 88 | +}; |
| 89 | + |
| 90 | +const WorkerComponent = () => { |
| 91 | + const [input, setInput] = useState(size); |
| 92 | + const { result, start, cancel } = useWorker(workerScript); |
| 93 | + |
| 94 | + const handleStart = () => { |
| 95 | + start(input); |
| 96 | + }; |
| 97 | + |
| 98 | + return ( |
| 99 | + <div> |
| 100 | + <input |
| 101 | + type="number" |
| 102 | + value={input} |
| 103 | + disabled |
| 104 | + onChange={(e) => setInput(parseInt(e.target.value, 10))} |
| 105 | + /> |
| 106 | + <button onClick={handleStart}>Start Worker</button> |
| 107 | + <button onClick={cancel}>Cancel Worker</button> |
| 108 | + <pre>{result ? JSON.stringify(result, null, 2) : 'No result'}</pre> |
| 109 | + </div> |
| 110 | + ); |
| 111 | +}; |
| 112 | + |
| 113 | +const SynchronousComponent = () => { |
| 114 | + const [input, setInput] = useState(size); |
| 115 | + const [result, setResult] = useState(0); |
| 116 | + |
| 117 | + const handleStart = () => { |
| 118 | + setResult(workerScript(input)); |
| 119 | + }; |
| 120 | + |
| 121 | + return ( |
| 122 | + <div> |
| 123 | + <input |
| 124 | + type="number" |
| 125 | + value={input} |
| 126 | + disabled |
| 127 | + onChange={(e) => setInput(parseInt(e.target.value, 10))} |
| 128 | + /> |
| 129 | + <button onClick={handleStart}>Start Synchronous</button> |
| 130 | + <div>Result: {result}</div> |
| 131 | + </div> |
| 132 | + ); |
| 133 | +}; |
| 134 | +``` |
0 commit comments