본문 바로가기
  • ANALOG CODE
  • AnalogCode
개발

Web Worker - 브라우저에서도 백그라운드 작업이 가능

by 아날로그코더 2023. 4. 8.
반응형

자바스크립트는 단일 쓰레드로 동작한다. 그래서 브라우저에서 자바스크립트로 시간이 오래걸리는 코드를 만나게 되면 UI는 멈추게 된다. 브라우저에서 자바스크립트로 시간이 오래 걸리는 작업을 하고 싶은 경우에 Web Worker를 사용하면 된다. Web Worker는 별도의 쓰레드에서 동작하여 메인쓰레드에 영향을 주지 않게 작업을 할 수 있다.

 

시간이 오래걸리는 작업 코드 예제

아래 코드에서 0부터 1000000000까지 더하는 코드가 시간을 많이 걸리는 코드이다.

브라우저에서 페이지를 열면 한동안 페이지가 로딩중으로 멈춰있다가 덧셈 연산이 모두 끝나면 결과가 출력되면서 페이지가 동작을 하게 된다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  </head>
  <body>
    <div id="sum">0</div>

    <script>
      var sum = 0
      for (let i=0; i<=1000000000; i++) {
        sum += i
      }
      document.getElementById('sum').innerHTML = sum
    </script>
  </body>
</html>

자바스크립트는 단일쓰레드이므로 덧셈연산이 끝나기 전까지 쓰레드를 독점하고 있으므로 UI도 출력이 될수가 없게 된다. 단일 쓰레드의 역할에는 UI렌더링까지 포함된다.

 

Web Worker 사용 코드

위 작업을 Web Worker를 사용하여 화면 멈춤이 없도록 바꾸어보자

Web Worker는 자바스크립트 파일로 만든다.

worker.js

// worker.js

var sum = 0

for (let i=0; i<1000000000; i++) {
  sum += i
}

postMessage(sum)

 

 

시간이 오래 걸리는 연산작업을 하는 코드이다. 

연산이 모두 끝나면 postMessage() 를 통해 worker를 호출한 페이지로 값을 전달한다.

 

- Worker 쓰레드에서 메인 쓰레드로 메세지 전달

postMessage(data) // data는 단순 숫자나 문자열부터 Object, Array와 같은 값들을 모두 보낼 수 있다.

worker가 동작하는 쓰레드와 호출한 쓰레드는 서로 다른 쓰레드이다. 이 2개의 쓰레드간에 메세지를 전달할 수 있는 함수가 바로 postMessage() 메소드이다.

worker 스크립트에서 postMessage()를 통해 sum 값을 보낸다.

 

- index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  </head>
  <body>
    <div id="sum">0</div>
    <button>Button</button>
    <script>
      var worker = new Worker('./worker.js')
      worker.onmessage = (e) => {
        document.getElementById('sum').innerHTML = e.data
        worker.terminate()
      }
    </script>
  </body>
</html>

 

Web Worker를 생성하고 메세지를 받아서 DOM을 갱신해주는 동작을 한다.

 

- Worker 쓰레드 생성

아래 코드로 Worker 쓰레드를 생성한다.

new Worker(URI) // URI: Worker 쓰레드에서 실행할 스크립트의 경로를 넣는다.

 

- Worker 쓰레드 메세지 수신

Worker 쓰레드로부터 postMessage()를 통해 메세지가 올 경우의 이벤트를 처리할 수 있다.

worker.onmessage = (e) => {
  // 받은 메세지 처리 e.data
}

우리는 e.data에 Worker 쓰레드에서 postMessage()로 전달해준 값이 들어있다.

이 값을 DOM 영역에 넣어주어서 화면에 보이게 만든다.

 

- Worker 종료

terminate() 메소드를 통해 Worker 쓰레드를 종료시킬 수 있다.

worker.terminate()

 

 

- 메인쓰레드에서 Worker 쓰레드로 메세지 전달

샘플코드에는 없지만 index.html 메인쓰레드에서 Worker 쓰레도로도 메세지 전달이 가능하다.

 

index.html

worker 객체의 postMessage() 메소드를 호출하여 데이터를 전달한다.

worker.postMessage(data)

 

 

worker.js

Worker 쓰레드에서는 onmessage 라는 핸들러를 작성하여 받은 메세지를 처리하는 코드를 넣어주면 되는 것이다.

onmessage = (e) => {
  // 메인쓰레드에서 받은 메세지 처리
}

 

마무리하며

Web Worker로 인해 브라우저에서도 이제는 멀티쓰레드 환경의 개발이 가능해졌다. 물론 대부분의 웹사이트에서는 굳이 Web Worker가 필요한 상황이 거의 없을 것이다. 어떤 상황에서 활용하면 좋을까?

 

아마도 Web Worker가 할일을 거의 서버에서 처리하고 브라우저로 결과를 알려주는 방식으로 처리가 가능하리라 생각한다. 이를 반대로 말하면 서버에서 해야될 비동기 작업을 각 클라이언트로 분산시킬 수도 있다는 얘기가 된다. 그러면 서버의 부담을 엄청나게 줄일 수 있다는 것이 된다. 물론 보안적인 이슈도 존재한다.

하지만 분명히 브라우저에서 UI가 멈추는걸 방지하면서 시간이 오래 걸리는 작업을 처리하면서 메인쓰레드로 중간 값들을 주는 처리를 하기에는 알맞은 기능이라 생각한다.

 

반응형

댓글