// 메인 스레드const myWorker =newSharedWorker('worker.js');
myWorker.port.onmessage= e =>console.log(`Message received from worker: ${e.data}`);
myWorker.port.start();<input type="text" onChange={e => myWorker.port.postMessage(e.target.value)}/>
// worker.jsonconnect= e =>{const port = e.ports[0];
port.addEventListener('message', e =>{const workerResult =`Result: ${e.data}`;
port.postMessage(workerResult);});// addEventListener 를 사용하기 위해서는 다음 코드가 필수입니다.// 아니라면, onmessage 메소드에서 암시적으로 호출합니다.
port.start();};
메인 스레드의 포트와 연결되기 위해 워커에서는 onconnnect 이벤트를 이용하며, e.ports 를 통해 (공유 워커의 포트에) 큐잉된 메세지들을 메인 스레드의 포트에 전송합니다.
첫번째 창에서 웹 워커와 상호작용한 모습
두번째 창에서 웹 워커와 상호작용한 모습
이렇게 서로 다른 브라우징 컨텍스트에서 동일한 웹 워커에 접근할 수 있습니다.
서비스 워커
서비스 워커는 기본적으로 프록시 서버의 역할을 수행합니다. 서비스 워커는 오프라인 경험을 개선하기 위한 목적으로 만들어졌습니다. 따라서 네트워크 요청을 가로채거나, 네트워크 연결 여부에 따라 적절한 조치를 취하는 등의 역할을 수행하는게 좋습니다. 추가로, 푸시 알림이나 백그라운드 동기화 API도 사용이 가능합니다.
스레드라고 한다면 당연히 공유 메모리와 같은 동시성과 관련된 문제들이 신경 쓰이실텐데요, 다행히 스레드 불안전 컴포넌트나 DOM에 접근할 수 없고, 직렬화된 데이터만 주고받을 수 있기 때문에 안전하다고 합니다.
웹 워커에서 사용가능한 함수 및 인터페이스들
Navigator
fetch API
Array, Date, Math, String
setTimeout, setInterval
등등
메인 스레드에 영향을 줄 수 있는 것들은 워커에서 사용할 수 없습니다. 따라서, DOM에 접근하는 것도 불가능합니다.
개인적인 감상
저는 실무에서 MSW를 제외하고는 웹 워커를 사용해본 적이 없는데요, 이번에 갑자기 궁금해져서 이리저리 찾아보고 테스트해봤습니다.
만약 동적으로 특정 함수를 위임하고 싶다면 eval 을 활용할 수도 있는게 재밌더라구요.
// 메인 스레드에서 즉시실행 함수 표현식을 문자열로 보냅니다.
myWorker.postMessage(`(() => 'im stringfied function!')()`);// 웹 워커에서 해당 문자열을 받아 eval 로 실행합니다.onmessage= e =>{const workerResult =`Result: ${eval(e.data)}`;};
물론 eval 은 엄청 위험한 녀석이니 조심해서 사용해야 합니다. 심지어 웹 워커는 자신만의 실행 컨텍스트를 가지므로, 워커 호출자(메인 스레드)의 Content Security Policy 도 적용받지 않으니 더욱 조심해야 합니다.
이 외에더 더 많은 정보들이 있지만, 이번 기록에서는 간단하게 무슨 종류가 있는지, 어떻게 사용하는지, 대표적인 주의점은 무엇인지 간단하게 훑어보았습니다.