Web Worker(multi thread)

y0ung·2021년 1월 13일
1

JavaScript

목록 보기
11/20
post-thumbnail

자바스크립트는 싱글 스레드로 동작 하는 언어이다. 하지만 웹워커를 사용하면 브라우저에서 멀티 스레드를 활용할수 있다.

왜 멀티 스레드가 필요하지?

싱글 스레드 방식에는 한가지 큰 단점이 있는데, 계산할 일이 많은 작업을 하는 경우, 그 작업이 완료되어야 다른 작업을 수행 할수 있다는 것이다. 예를 들면, 웹 게임에서 좌표를 계산하는 데 3초가 걸리고 계산된 좌표를 받아 DOM에 반영한다고 하자. 좌표를 계한 하느라 3초간 DOM업데이트 등의 다른 작업들을 수행할 수가 없다. 사용자 입장에서는 3초간 멍하니 기다릴 뿐이다. 좌표를 동시에 여러번 계산해야 하는 경우 시간은 더 늘어나게 된다.

짧은시간은 어쩔수 없다 치더라도, 게산하는 동안 UI 클릭 같은 다른 작업은 진행할 수 있어야 원활한 서비스를 제공할 수 있다. 이럴때 워커가 사용된다.

Web Worker

웹워커는 멀티 스레드 기능을 지원하며 워커가 생성될 때마다 자바스크립트를 실행할 수 있는 고유 스레드를 생성하여 속도 성능을 크게 향상시킬 수 있다. 워커에서 실행하는 코드는 브라우저 UI에도, 다른 워커에서 실행하는 코드에도 영향을 주지 않는다. 즉, 독립적으로 실행되는 멀티스레드 이다.

Web Worker _ mdn

웹워커가 사용되는 상황

  • 매우 큰 문자열의 암호화/ 복호화
  • 복잡한 수학계산(이미지/비디오 처리 포함)
  • 매우 큰 배열의 정렬
    즉 로딩과 실행이 오래 걸리는 자바스크립트 파일

워커 사용 예제

워커는 DOM에 직접 접근하지 못하기 때문에 메인 스레드와 서로 메시지를 주고 받아서 통신한다. iFrame과 통신하는 것과 API가 매우 유사하다. 아래는 워커를 활용하는 예제이다.

<div id="result"></div>
<button id="btn">run</button>
<script>
function sleep(delay) {
  let start = new Date().getTime();

  while (new Date().getTime() < start + delay);
}

document.querySelector("#btn").addEventListener("click", () => {
  sleep(3000);
  let div = document.createElement("div");

  div.textContent = Math.random();

  document.querySelector("#result").appendChild(div);
});

</script>

run버튼을 누르면 3초동안 다른작업을 할수 없게 된다.(싱글스레드)
위의 상황을 웹워커를 사용해서 개선해 보자

document.querySelector("#btn").addEventListener("click", () => {
  let worker = new Worker("./worker.js");
  console.log(worker);
  
  worker.addEventListener("message", (e) => {
    let div = document.createElement("div");
    
    div.textContent = e.data;
    
    document.querySelector("#result").appendChild(div);
    
    worker.terminate();
  });

  worker.postMessage("일해라 워커야!!");
});

버튼을 누를때, 직접 계산하는 것이 아니라 워커를 생성하고 워커에게 postMessage로 일하라고 알린다. 워커에 message 이벤트 리스ㅌ너를 붙이는 것은 워커로부터 결괏값을 받기 위함이다. e.data로 받아올수 있다. 결괏값을 DOM에 반영한 후에는 terminate 메소드로 워커를 종료한다. 워커(worker.js)는 다음과 같다

postMessage

해당 메소드에 전달 될 수 있는 인자 타입 값은 String, Integer, Boolean, null, undefined, Object, Array이다.

function sleep(delay) {
 var start = new Date().getTime();
 while (new Date().getTime() < start + delay);
}
self.addEventListener('message', function(e) {
  console.log(e.data); // 일해라 워커!
  
  sleep(3000); // 3초가 걸림을 표현
  
  var coords = Math.random();
  
  console.log(coords);
  
  self.postMessage(coords);
});

계산하는 로직이 워커로 이동했다. 워커도 postMessagemessage이벤트 리스너르 사용한다. 마스터에게 메시지를 보내고 받는 것이다. 워커는 새로운 스코프를 형성하기 때문에 slef라는 키워드로 자기 자신과 연결한다(this도 가능하지만 this는 상황에 따라 값이 달라질수 있다). postMessage에 넣은 인자가 e.data로 연결된다.

복잡한 연산은 다른 스레드가 계산하게 해주고 결과만 나중에 돌려주기 때문에 웹워커는 매우 유용하다.

워커가 다른 워커를 불러올 수도 있다.

// worker2.js
self.a = 'hello worker!'

worker.js에서 worker2.js의 self를 불러올수 있다.

self.addEventListener('message', function(e) {
  a = 'ignored';
  importScripts('./worker2.js');
  
  console.log(a); // hello worker!
});

importScripts 함수로 불러오면 된다. self에 변수를 추가하는 것에 유의 해야 한다. 이래야만 다른 워커에서 사용할수 있다.

워커에는 DOM에 접근하지 못하는것 외에도 사용할수 있는 API에 제약이 있기 때문에 사용가능한 목록을 확인 하는 것이 좋다. _ 목록 살펴보기

대부분의 웹에서는 워커를 쓸 정도로 복잡한 작업을 진행하지 않기 때문에 웹워커를 사용하는 일이 드물다. 하지만 빅데이터 처리나 웹 게임 등의 경우에는 유용하다.

profile
어제보다는 오늘 더 나은

0개의 댓글