March 19, 2023
실무에서 웹 워커를 적용하면서 고민했던 내용을 기록합니다.
실무 프로젝트에서는 Vue 3
Vuex
Typescript
Webpack 5
환경으로 구성되어 있는 점 참고 바랍니다.
실시간으로 대용량의 데이터를 차트, 그리드로 렌더링하는 과정에서 성능 이슈가 발생하여 도입하게 되었습니다.
적용하면서 고민한 내용은:
그렇다면 이제 고민한 내용을 살펴보겠습니다.
API 요청 시 토큰 인증이 필요한데 이를 위한 토큰 관리를 어느 스레드에서 할지 고민이었습니다.
Case 1. Session Storage를 선택했습니다.
그 이유는:
프로젝트에서 Vuex를 사용하여 개발하고 있기 때문에 위와 같은 상태관리패턴을 적용하고 있는 상태이다. 하지만 웹 워커를 도입한다면 어떤 패턴을 적용해야할지 고민이었습니다.
Case 2. Vuex를 거쳐서 웹 워커를 동작시키는 방식을 선택했습니다.
이유는:
메인 스레드와 워커 스레드 간의 데이터를 주고받을 때 명확한 규칙 필요성을 느꼈습니다.
이전에 공부한 내용을 토대로 JSON-RPC 방식에 착안하여 워커스레드에 method, params를 Object 형식으로 전달하는 패턴과 명령 분배 패턴을 적용했습니다.
웹 워커를 적용하면서 가장 주의한 부분은 ‘웹 워커의 비동기 처리를 메인 스레드에서 기다리지 않도록 구현해야겠다’ 였습니다. 그 이유는 위의 사진처럼 웹 워커의 비동기 처리를 기다리는 동안 메인 스레드는 블로킹 상태가 되기 때문입니다. 제가 느끼기에는 반쪽짜리 멀티 스레드처럼 보였습니다.
하지만 막상 적용해보니 동기적으로 수행해야하는 케이스가 존재해서 골머리였습니다.
비동기 로직을 실행하는 execute
함수의 실행 시점을 제어할 수 있도록 만들어서 비동기 처리와 동기 처리를 둘 다 지원하도록 해결했습니다.
이제 모든 고민들이 해결되가고 있었습니다. 하지만 기존 코드에 워커를 적용하는 거라 이를 바꿀 때의 시간적인 비용이 많이 소요될 것 같았습니다. 저는 이를 줄이기 위해서 Composable 함수를 따로 만들었는데요, React에서 Custom hook이 있다면 Vue에서는 Composable 이라는 용어로 사용하고 있습니다.
Composable 이란?
Vue Composition API에서 재사용 가능한 로직을 캡슐화하여 제공하는 함수입니다.
참고 링크
useAsync
함수를 합성하여 워커에서 처리하는 데이터, 로딩, 에러, 실행 함수를 제공하여 반복되는 코드를 재사용할 수 있도록 개발했습니다.
이로 인해 기존 코드에서 수정 작업을 할 때 수월하게 작업할 수 있었습니다.
실시간 모니터링 화면의 FPS가 50 -> 60을 유지하는 것을 확인할 수 있었습니다. 또, 대용량 데이터 처리 시 발생하던 성능 이슈를 개선할 수 있었습니다.
최종적으로 기존에 Vuex에서 담당하던 계산 로직, API 호출을 웹 워커에 위임한 모습으로 바뀌었습니다. 이 과정에서 팀원분들과 협의되지 않았던 역할군에 대해 확립하는 계기가 되었습니다.
API 요청하는 역할은 워커가 하지말고, 계산 로직만 수행하는 방법을 적용했다면 어땠을까 아쉬움이 남습니다. 생각보다 API 요청, 응답 과정에서 많은 전처리가 들어가는데 이를 워커 스레드에서 관리하는 게 힘들었습니다. 버그 핫스팟이 전처리 과정이었습니다😂
Vue를 사용하면서 웹 워커를 사용한 사례가 없어서 힘들었습니다. 그 밖에 TypeScript, Webpack5도 고려하다보니 환경 구성부터 예상치 못한 에러가 많았습니다.
다행히 책과 인터넷을 뒤져가며 많은 시행착오 끝에 고민했던 부분을 해결할 수 있었습니다.