브라우저 메인 스레드의 10ms 예산: JS·렌더링 경합을 나누고 옮기는 법
- 브라우저 메인 스레드는 JavaScript, 이벤트·타이머·네트워크 콜백과
requestAnimationFrame, 스타일 계산, 레이아웃, 페인트를 직렬로 처리하며, 합성 단계만 별도 컴포지터 스레드가 맡음 - 60Hz 화면의 프레임 간격은 약 16.6ms지만 브라우저 자체 비용을 빼면 실사용 예산은 약 10ms이고, 120Hz에서는 이 예산이 절반으로 줄어듦
- 한 JavaScript 작업이 실행되는 동안 메인 스레드는 화면을 다시 그리거나 클릭을 처리하지 못하며, 50ms 초과 작업은 일반적으로 문제가 되는 long task로 봄
- 글은 메인 스레드 작업을 분할·일괄 처리·우선순위화·지연하고, 컴포지터나 Web Worker로 옮기거나 작업 자체를 없애는 방법을 다룸
Hacker News opinions
텍스트 위주 사이트가 쓸데없는 작업을 안 하면 메인 스레드 최적화 자체가 별 문제 아닐 때가 많다고 봄. 웹페이지 대부분이 광고용 잡일을 너무 많이 함.
텍스트만 있는 사이트가 아닌 웹앱도 많음. 모바일 개발에서는 메인 스레드를 비우라는 얘기가 익숙한데, 웹 개발 쪽에서 이만큼 잘 정리한 글은 처음 봤음.
HN 같은 사이트와 earth.nullschool.net 같은 시각화 사이트는 요구사항이 다름. 애니메이션과 렌더링을 전부 불필요하다고 할 수는 없음.
이미지, 애니메이션, 고빈도 업데이트가 필요하면 이 글의 접근이 유용함. React가 양보하려고 MessageChannel에 메시지를 보낸다는 것도 처음 알았음.
첫 예제에서 입력 중 2.0초 버튼을 누르면 입력칸 포커스가 사라지는 것 아닌가 싶었음. 요점은 그 2초 동안 다시 포커스할 수도 없다는 데 있는 듯.
4,000개 파티클 예제는 렌더링을 5ms씩 나눈 경우와 한 번에 처리하는 경우의 동작 차이가 흥미로웠음. 다소 반복적이긴 해도 예제가 잘 보였음.
WASM으로 문서 렌더링을 만들고 있어서 Web Worker를 검토 중임. ArrayBuffer가 참조만 옮겨진다는 설명은 쓸 만한 선택지로 보였음.
문서 작업은 안 해봤지만 캔버스 렌더링에는 transferControlToOffscreen()이 ArrayBuffer 이동보다 나았음. 캔버스를 워커에 넘기면 postMessage로 픽셀을 보낼 필요 없이 워커가 직접 그림.
JavaScript의 await가 조건부로 양보할 수 있으면 좋겠음. 지금은 if (shouldYield()) await doYield() 같은 우회법을 써야 해서 불편함.
화면 밖 글을 빈 껍데기로 두는 가상화는 브라우저 검색을 망가뜨림. Reddit, Outlook 웹, Bluesky에서 특히 답답했고 자체 검색도 형편없음.
DOM에 항목을 수천 개씩 가상화 없이 넣으면 좋은 컴퓨터도 버거워짐. 사이트가 자체 검색을 제대로 구현하면 되는데 안 하는 것이 문제지, 가상화 자체를 탓할 일은 아님.
희소한 자원에 작업을 배분하는 문제는 컴퓨터 과학에서 오래 연구했음. 스케줄링을 개발자 경험과 판단의 문제로만 마무리하기보다 교과서를 참고했어야 한다고 봄.
브라우저에서는 워커, 메시지, 공유 메모리, 양보 같은 제한된 원시 기능 안에서 풀어야 함. 기존 스케줄링 연구를 버릴 이유는 없지만, 제어 가능한 환경을 가정한 모델을 그대로 적용하기도 어려움.
2024년형 삼성 A15에서 느린 가격표 예제는 11fps, 빠른 예제는 30fps가 나왔음. 스크롤하면 15fps까지 떨어졌는데 글에서 말한 백프레셔 사례인지 궁금함.
이 글을 AI가 쓴 글이라고 부르는 반응이 이해 안 감. 오래 이 분야에서 일했는데 문장이나 내용에서 뚜렷한 AI 흔적 없이 차분하고 정확하게 쓴 글로 보였음.
원문은 한국어로 쓰고 영어로 번역한 글임. 긴 글이라는 이유만으로 AI 슬롭이라 부르는 쪽이 성급한 판단 같음.
글에서 소개한 기법은 실제로 느린지 확인한 뒤에 적용해야 함. 빠진 도구로는 Chrome Performance Monitor가 먼저 떠오름.