본문 바로가기
Project/스타게이트

Web Worker로 백그라운드에서 타이머 작동시키기

by 이의찬 2024. 3. 19.

0.TL;DR

  • 기존의 타이머 수정방안 3가지 모두 서버 리소스와 UX측면에서 약간의 손해를 감수해야 했기에 아쉬웠음
  • JavaScript의 비동기 처리 브라우저의 멀티 스레드 동작, 그리고 백그라운드 스레드에서 동작하는 Web Worker 학습
  • 이후 Web Worker를 사용해서 background에서 타이머가 동작하도록 해 문제 해결

1. Why?

스타게이트에서 타이머를 동작시키는 과정에서, 백그라운드로 탭이 넘어갈 시 1000ms에 한 번 동작해야 할 타이머가 60000ms에 한 번 동작하게 되는 문제점이 있었다. 이를 해결하기 위해 Page Visibility API로 타이머가 정상적인 값을 보내주도록 처리했었다.

 

setInterval과 Page Visibility API로 정확한 대기시간 알려주기

1. Why? 삼성청년SW아카데미에서 진행한 프로젝트들의 회고가 너무 부실해서 수정하는 중이였다. 첫 번째로 스타게이트 회고를 수정하고 있었는데, 문득 타이머에 문제가 있었던 것이 떠올랐다.

cksxkr5193.tistory.com

하지만, 사용을 고민했던 3가지 방안 모두 서버 리소스와 UX측면에서 약간의 손해를 감수해야 했기에 아쉬움이 있었다.

 

그래서 더 나은 방법을 찾아보던 중 Web Worker를 사용하면 탭이 백그라운드로 넘어가도 계속해서 타이머가 동작하도록 할 수 있다는 것을 알게되었다. 고로 이번 글에서는 Web Worker에 대해서 학습하고, 스타게이트에 적용시켜보고자 한다.


2. Web Worker

1) Web Worker의 필요성

  • JavaScript는 싱글 스레드 언어이다. 그렇기에, 기본적으로는 순차적으로 동작한다.
  • 하지만 브라우저는 싱글 스레드로 동작하지 않는다. 
  • Web Worker는 멀티 스레드 작업이 필요할 경우, 메인 스레드와는 별개의 백그라운드 스레드를 사용하는 것이다.

출처 : https://tech.kakao.com/2021/09/02/web-worker

위의 이미지를 보자

  • 좌측은 Web Worker가 없기에 순차적인 방식으로 UI 조작과 데이터 핸들링을 처리한다.
  • 우측은 Web Worker를 사용하기에 UI 조작, 데이터 핸들링 병렬 처리가 가능하다.
    • UI 조작이 즉각적으로 이뤄져야하기에 보통 메인 스레드가 UI 조작을, 워커 스레드가 다른 작업을 하게 된다.

2) Web Worker란?

이를 알기 위해서는 우선 JavaScript의 동작부터 이해해야한다.

JavaScript의 동작

  • 콜 스택
    • JavaScript가 실행될 때, 실행되는 함수가 쌓이는 스택이다. 
    • Js는 싱글 스레드 언어이기에, 한 번에 하나의 함수만 처리할 수 있다.
    • 실행이 완료된 함수는 스택에서 제거된다.
  • 메세지 큐(태스크 큐, 콜백 큐)
    • 비동기 작업(setInterval, 네트워크 요청 등)이 실행되면, 각자의 실행환경(ex)setInterval이라면 Web API)으로 넘어간다.
    • 실행이 완료되면 결과값을 가진 콜백 함수가 여기서 대기한다.
  • 이벤트 루프
    • 콜 스택이 비어 있을 때, 메시지 큐에서 다음 작업(콜백 함수)를 가져와서 콜 스택에 추가해준다.

이를 통해서 싱글 스레드인 JavaScript가 비동기적으로, 블로킹 없이 동작할 수 있다.

Web Worker

출처 : https://tech.kakao.com/2021/09/02/web-worker

  • 동작
    • Web Worker는 자신만의 콜 스택, 이벤트 루프, 메세지 큐를 가진다.
    • 메인 스레드와는 독립적인 환경에서 동작한다.
    • 만약 Worker 내부에서 비동기 작업이 요청된다면? Worker의 이벤트 루프에 의해 처리된다.
  • 메인 스레드와의 통신
    • 메세지 기반으로 통신이 이뤄진다. 메세지를 보낼때는 postMessage, 받을 때는 onmessage를 사용한다.
  • 메인 스레드와의 차이점
    • 메인 스레드와는 별개의 글로벌 컨텍스트를 가진다.
    • DOM에 직접 접근이 불가능하다. 

3) 그래서 언제 쓰면 되나요?

이럴 때 쓰세요

  1. 클라이언트 단에서 처리해야하지만 복잡하고 시간이 오래 걸리는 로직이 있는 경우
  2. 이번처럼 비활성화시에도 계속해서 동작해야하는 경우

비활성화 5분 후

이럴 땐 다시 생각해보세요

출처: https://medium.com/teads-engineering/the-most-accurate-way-to-schedule-a-function-in-a-web-browser-eadcd164da12

  1. 브라우저에서 Web Worker를 지원해줘야 하기에, 지원되지 않는 구형 브라우저까지 생각해야하는 경우
    • 단, IE에서도 지원하니 어지간하면 거의 모든 브라우저가 지원한다.
  2. 복잡하고 시간이 오래 걸리는 로직이 아닌 경우 or 서버에서 처리하는게 더 유리한 경우
    • 복잡한 로직이 아니라면 굳이 Web Worker를 사용하기보다 그냥 비동기 처리가 더 나을 수 있다.
  3. Dom 조작이 필요한 경우
  4. 추가적인 비용이 발생하기에, 정말 필요한지 잘 모르는 경우
    • 아래의 timerWorker는 1000ms에 한번 메시지를 전송하는 간단한 로직임에도 400kb의 메모리를 소모한다.


3. How?

timerWorker.ts

setInterval(() => {
  postMessage('1000ms');
}, 1000);
  • 1000ms에 한 번, 메인 스레드로 메시지를 보내는 timerWorker다.
  useEffect(() => {
      if (isV8 && window.Worker) { 
        const worker = new Worker(
          new URL('./timerWorker.ts', import.meta.env.VITE_SERVER_URL)
        );
        worker.onmessage = () => {

        // 상태 변경 코드

        };
        return () => worker.terminate();
      } else {
      
      // 기존 타이머 코드
      
      }
  }, [data, setData]);
  • 보정이 들어가지 않는 브라우저거나, Web Worker가 지원되지 않을 경우 타이머가 정상적으로 작동하지 않을 수 있다.
  • 이 경우 Web Worker를 사용하는 대신, 상대적으로 자주 데이터를 가져오는 기존의 방식을 그대로 사용하도록 했다.

주의해야할 점

  • 번들링 환경에서는 ./timerWorker.ts만 적어두면 경로를 찾지 못한다. 
  • 그래서 import.meta.url을 사용해 절대 경로로 웹 워커를 참조하도록 경로를 설정해줘야 한다.

 

 


4. 래퍼런스

https://tech.kakao.com/2021/09/02/web-worker/

 

브라우저 Web Worker 다루기 with 오피스 문서 텍스트 추출 및 암호해제

안녕하세요. 톡플랫폼개발팀 bishop.cho입니다. 현재 메일클라개발셀에서 프론트엔드 업무 개발을 담당하고 있습니다. 기존에는 자바스크립트로 동작하는 오피스 에디터 및 뷰어 개발을 했던 경

tech.kakao.com

https://www.zerocho.com/category/HTML&DOM/post/5a85672158a199001b42ed9c

 

(HTML&DOM) 웹 워커 - 멀티 쓰레드 활용하기

안녕하세요. 이번 시간에는 웹 워커에 대해 알아보겠습니다. 자바스크립트는 싱글 쓰레드로 동작하지만 웹 워커를 사용하면 브라우저에서 멀티 쓰레드를 활용할 수 있습니다. 왜 멀티 쓰레드가

www.zerocho.com

 

https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%B8%94%EB%A1%9C%ED%82%B9%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC

 

👩‍💻 완벽히 이해하는 동기/비동기 & 블로킹/논블로킹

동기/비동기 & 블로킹/논블록킹 프로그래밍에서 웹 서버 혹은 입출력(I/O)을 다루다 보면 동기/비동기 & 블로킹/논블로킹 이러한 용어들을 접해본 경험이 한번 쯤은 있을 것이다. 대부분 사람들은

inpa.tistory.com

이벤트 루프 - JavaScript | MDN (mozilla.org)

 

이벤트 루프 - JavaScript | MDN

JavaScript의 런타임 모델은 코드의 실행, 이벤트의 수집과 처리, 큐에 대기 중인 하위 작업을 처리하는 이벤트 루프에 기반하고 있으며, C 또는 Java 등 다른 언어가 가진 모델과는 상당히 다릅니다.

developer.mozilla.org

https://ko.vitejs.dev/guide/features#web-workers

 

Vite

Vite, 차세대 프런트엔드 개발 툴

ko.vitejs.dev

 

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/import.meta

 

import.meta - JavaScript | MDN

import.meta 속성은 모듈의 메타 데이터를 JavaScript 모듈에 노출합니다. 여기에는 URL과 같은 모듈에 대한 정보가 포함됩니다.

developer.mozilla.org

https://medium.com/hcleedev/web-web-worker-%EC%82%AC%EC%9A%A9%EB%B2%95%EA%B3%BC-%EC%A3%BC%EC%9D%98%ED%95%A0-%EC%A0%90-webpack-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%AC%B8%EC%A0%9C-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%AA%A8%ED%82%B9-2d77c5b23afe

 

Web: Web Worker 사용법과 주의할 점(webpack, 메모리 문제, 테스트 모킹)

Web Worker와 이를 사용하면서 경험한 몇몇 문제점들에 대해 알아보자

medium.com