타입스크립트에서의 웹 워커
이 기사에서는 타입스크립트에서 웹 워커에 대해 설명합니다.
Web Worker
의 개념과 다양한 사용 팁을 예제를 통해 배울 수 있습니다.
YouTube Video
타입스크립트에서의 워커
타입스크립트에서 Worker
는 JavaScript 웹 워커 API를 활용하여 메인 스레드와 분리된 백그라운드에서 처리를 수행하는 메커니즘입니다. 이를 통해 무거운 계산 작업과 비동기 태스크를 사용자 인터페이스의 동작에 영향을 주지 않고 실행할 수 있습니다.
Worker
는 메인 스레드(UI 스레드)와 병렬로 동작하며 메시지를 통해 스레드 간 데이터를 교환할 수 있습니다. 타입스크립트에서도 타입 안전한 코드를 작성하면서 Worker
를 사용할 수 있습니다.
워커의 기본 사용법
-
워커 생성하기
Worker
인스턴스를 생성하고 지정된 스크립트를 실행합니다. 일반적으로 스크립트는 별도의 파일로 정의됩니다. -
메시지 교환
postMessage
와onmessage
를 사용하여 메인 스레드와Worker
스레드 간 메시지를 주고받습니다.
예제: 기본적인 워커 구현
- worker.ts: 워커를 위한 스크립트
1// worker.ts
2self.onmessage = (event) => {
3 const data = event.data;
4 const result = data.num1 + data.num2;
5 self.postMessage(result); // Return the result to the main thread
6};
- main.ts: 메인 스레드에서 워커를 사용하는 스크립트
1// main.ts
2const worker = new Worker(
3 new URL('./worker.ts', import.meta.url),
4 { type: 'module' }
5);
6
7worker.onmessage = (event) => {
8 console.log("Result from worker:", event.data); // Receive message from the worker
9};
10
11worker.postMessage({ num1: 10, num2: 20 }); // Send message to the worker
- 이 예제에서
worker.ts
는 별도의 스레드에서 실행되며,num1
과num2
의 합계를 계산하여 메인 스레드로 반환합니다. 메인 스레드는 결과를 받아서 콘솔에 출력합니다. type: 'module'
을 지정하면, 워커 스크립트가 ES 모듈로 해석되어import
와export
를 사용할 수 있습니다. 이렇게 하면 기존의importScripts()
를 사용하지 않고도 모듈 구조를 처리할 수 있습니다.
타입스크립트에서 워커 사용 시 주의할 점
타입 정의 추가하기
타입스크립트에서는 메시지를 송수신할 때 타입 안전한 상호작용을 보장하기 위해 데이터 타입을 정의합니다.
1// Define data types
2interface WorkerData {
3 num1: number;
4 num2: number;
5}
6
7interface WorkerResult {
8 result: number;
9}
10
11// worker.ts
12self.onmessage = (event: MessageEvent<WorkerData>) => {
13 const data = event.data;
14 const result = data.num1 + data.num2;
15 const message: WorkerResult = { result };
16 self.postMessage(message); // Send the result in a type-safe manner
17};
18
19// main.ts
20const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
21
22// Type the event from the worker
23worker.onmessage = (event: MessageEvent<WorkerResult>) => {
24 console.log("Result from worker:", event.data); // event.data is number
25};
26
27// Send typed data to the worker
28const message: WorkerData = { num1: 10, num2: 20 };
29worker.postMessage(message);
MessageEvent
의 타입 매개변수를 지정하여 수신할 데이터의 타입을 명확히 정의할 수 있습니다. 이를 통해 타입 안전성을 갖춘 데이터 교환이 가능합니다.
Webpack 또는 Vite 설정하기
TypeScript에서 Worker
를 사용할 때, Webpack
이나 Vite
와 같은 번들러가 필요할 수 있습니다. 이 도구들을 사용하면 Worker
스크립트를 올바르게 번들링하고 메인 스레드에서 사용할 수 있습니다.
예를 들어, Vite
를 사용할 때는 import.meta.url
을 활용하여 Worker
를 올바르게 가져올 수 있습니다.
1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
- 이렇게 하면 번들링된
Worker
스크립트가 올바르게 로드되어Worker
를 활용한 처리가 가능합니다.
메시징 및 동시성에 대한 고려사항
-
데이터 복사
메인 스레드와
Worker
스레드 간 메시지를 주고받을 때 데이터가 복사됩니다. 객체와 같은 복잡한 데이터를 다룰 때는 효율성을 고려해야 합니다. 대량의 데이터를 자주 교환하면 성능이 저하될 수 있습니다. -
전송 가능한
객체ArrayBuffer
와 같은 일부 객체는Transferable
객체라고 불립니다.Transferable
객체는 메시지 전송 시 복사가 아니라 Worker로 전송될 수 있습니다. 이를 통해 데이터 복사에 따른 오버헤드를 피할 수 있습니다.
1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
2
3const buffer = new ArrayBuffer(1024);
4worker.postMessage(buffer, [buffer]); // Transfer ownership to the Worker
5
6console.log(buffer.byteLength); // 0 (ownership moved)
-
두 번째 인자로
[buffer]
를worker.postMessage()
에 전달하면,buffer
는 복사되지 않고 Worker로 전송(이관)됩니다. -
이후 메인 스레드의
buffer
는 비어 있게 되며(byteLength
가 0) Worker만 사용할 수 있게 됩니다.
Worker
종료하기
Worker
를 사용한 후 종료하면 메모리 소비를 최소화할 수 있습니다. terminate
메서드를 사용하여 Worker
를 종료할 수 있습니다.
1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
2// ...
3
4worker.terminate(); // Terminate the Worker
- 이 코드는
terminate
메서드를 사용하여 Worker를 종료합니다.
Worker
에서의 예외 처리
Worker
내에서 오류가 발생하면 onerror
이벤트를 사용하여 오류를 처리할 수 있습니다.
1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
2
3worker.onerror = (error) => {
4 console.error("Error in Worker:", error.message);
5};
- 이 코드는
onerror
이벤트를 사용하여 Worker 내부에서 발생한 오류를 감지하고 처리합니다.
요약
TypeScript에서 Worker
를 사용하면 백그라운드에서 무거운 작업을 수행하면서 메인 스레드를 부드럽게 유지할 수 있습니다. 타입 정의를 사용하면 메시지 교환도 타입 안전하게 수행할 수 있습니다. 데이터 교환과 스레드 관리를 신경 쓰면 성능 개선과 효율적인 동시성을 달성할 수 있습니다.
위의 기사를 보면서 Visual Studio Code를 사용해 우리 유튜브 채널에서 함께 따라할 수 있습니다. 유튜브 채널도 확인해 주세요.