JIGGAG

3월 한달동안 로그

2025년 4월 17일

(번역) 자바스크립트에서 긴 작업을 분할하는 다양한 방법

  • 메인 스레드에서 길고 부하가 큰 작업을 실행할때
    • 큰 작업을 이벤트 루프의 여러 틱에 걸쳐 주기적으로 분할하는 것
    • 그 중간중간 다른 작업을 실행할 수 있도록
  • 가장 자주 접했던 방법 setTimeout을 반복 하는 것
    • setTimeout으로 실행한 콜백은 매크로태스크 큐에 쌓이고 이벤트 루프 돌면서 실행할 수 있기 때문에 분할되는데
    • setTimeout 안에서 재귀로 호출하게 되면 일정 주기로 작게 분할된 작업을 실행하도록 할 수 있다
  • async/await + Promise로 분할
    • 큰 작업 중간에 단순하게 Promise로 대기하는 로직을 추가한다
    • await new Promise(resolve => setTimeout(resolve, 0))
    • Promise의 resolve는 마이크로태스크 큐에 쌓이기 때문에 다음 이벤트 루프에서 실행된다
    • 다음 이벤트 루프 사이클로 넘겨라 하는 의미
      • await를 만나면 작업하던 것을 멈추고 이벤트 루프에게 권한을 넘긴다
      • setTimtout(resolve, 0) 을 다음에 실행할 매크로태스크 큐 넣어두고
      • Promise의 콜백을 마이크로태스크에서 꺼내 실행하고 다음 매크로태스크에 들어가며 resolve까지 실행되는 순서
  • setTimeout과 Promise 각각의 큐
    • 매크로태스크 vs 마이크로태스크
    • 이벤트 루프 돌면서 콜스택이 비어있을때 마이크로태스크 모두 실행되고 그 다음 매크로태스크가 실행된다
    • 그렇다면 먼저 실행되어야하는 것이 있다면 Promise.then 을 사용하고 그 다음 순위로 실행될 작업에 setTimeout 을 해주면 된다
  • 분할하다보니 requestAnimationFrame가 떠오르는데
    • 브라우저의 화면 갱신 주기와 동기화하여 작업을 예약하도록 설계되었습니다
    • 콜백은 항상 다음 화면이 렌더링 되기 직전에 실행
    • 렌더링 애니메이션 프레임 단위로 실행되는 requestAnimationFrame는 화면 끊김 없이 UI 작업이 진행되어야하는 경우
    • setTimeout은 순서는 중요하지 않으며 무거운 비동기 작업을 분할하여 실행해야하는 경우
  • 그렇다면 화면 끊김 없이 무거운 비동기 동작을 필요로한다면…
    • requestAnimationFrame만으로는 문제가 발생한다
      • 그러나 화면 갱신 주기에 맞춰 무거운 작업을 실행하면 렌더링 성능이 저하될 수도 있습니다.
      • 화면 갱신 주기와 동일하게 항상 실행되고 있으니 오히려 무거운 작업을 실행했을때 렌더링이 되지 않은 상태로 대기하는 것
    • requestAnimationFrame와 setTimeout 을 조합해야하는데
    • 어떤 형태가 되어야할까? requestAnimationFrame(setTimeout)
    • 화면끊김이 우선이니 🤔
  • 항상 작업 분리를 하다보면 웹 워커에 도달하게 되는데
    • 리액네에는 존재하지 않다보니 금방 패스 하게 된다
    • 브릿지 모듈로 네이티브를 다녀오거나
    • 렌더링 퍼포먼스는 극악의 최적화를 해야한다

(번역) Create-React-App 지원 중단 안내

  • 처음 리액트를 공부하기 시작했을때
    • 우선 고고 를 외치면 프로젝트 만들때 사용했던 CRA
    • 이게 프레임워크 인줄 알았다
    • 적절하게 프로젝트 환경이 구성되어있었기에
    • 리액트 = CRA = 프레임워크 라는 흐름으로 🏄
  • 이러한 문제를 해결하기 위해 사용자는 결국 CRA 위에 자신만의 맞춤형 솔루션을 구축하게 되는데, 이는 원래 CRA가 해결하고자 했던 문제이기도 합니다.
    • 프레임워크를 사용함으로써 얻을 수 이점이 있는데
    • 프로젝트마다 요구하는 구성이 다르기에 각각 자신만의 프레임워크를 구축하게 되지 않을까
    • 모든 곳에 완벽한 것은 없으니 계속 다양한 성격의 진화를 하게 되는듯

[번역] 리액트 19 forwardRef 지원 중단: 앞으로 ref를 전달하기 위한 표준 가이드

  • ref를 전달하고 이를 전달 받기 위해 forwardRef를 사용했는데 이게 없어진다고?
    • 표준 프로퍼티로 ref를 직접 전달
    • 컴포넌트 아키텍처를 간소화하고 보일러플레이트 코드를 줄이고자
    • 🥳 ref > forwardRef > ref…
    • 보일러 플레이트를 줄인다는 것에 감동
  • 그럼 리액트 19에서는 이걸 어떻게 접근할 것인가?
    • ref를 다른 props와 동일하게 사용한다
    • 🤔 왜인지 속상하다

[번역] 에포크 시맨틱 버전(Epoch Semantic Versioning)

  • 시맨틱 앞에 더 있다니!
  • MAJOR.MINOR.PATCH
    • 업그레이드 시 호환성과 안정성을 보장하기 위한 라이브러리 관리자와 사용자 간의 **계약**
    • 어떤 버전이 올라갔는지를 보고 어떤 목적의 업데이트가 이뤄진건지 추측할 수 있다는 것
  • {EPOCH * 1000 + MAJOR}.MINOR.PATCH
    • 메이저의 단계를 분할하여 조금 충격적이 것을 에포크 버전으로 올리자는 것인데…
    • 같은 의미로 쓰이던 메이저 버전을 조금 더 세분화 하는 느낌이라
    • 충격적인 의미를 전달하는 목적이라면
    • 버전 범핑이 1, 2, 3 순서대로가 아니라 1, 2, 10, 20 이런식으로 가도 되는 것 아닌가?
    • 그게 바로 에포크 인가