데이터베이스 커넥션 화면에서 연결한 데이터베이스의 종류를 고르는 화면을 만들고 있었다. 각각의 데이터베이스에 따라 입력하는 값이 달라질 수 있기 때문에 동적으로 화면을 그려야하는 상황이었다. 리액트에서 지원하는 컴포넌트를 이용해서 화면을 만들었는데 체감상 1~2초 정도 대기하는 것을 느꼈다. 의아하게 느꼈던 것은 네트워크 통신을 하는 다른 웹에서도 이렇게 느리지는 않았기에 내가 작성한 코드에 문제가 있다고 생각을 하였고

먼저 간단하게 이벤트마다 시간을 남겨서 비교를 해보았는데 시간 차이만 확인할 수 있었고 더 자세한 내용을 확인하기 힘들었다.

<select
  value={value}
  onMouseDown={() => console.log('[mousedown]', Math.round(performance.now()))}
  onClick={() => console.log('[click]', Math.round(performance.now()))}
  onChange={(e) => {
    console.log('[change-raw]', Math.round(performance.now()));
    onChange(e.target.value as Driver);
  }}
>

mousedown은 드롭다운을 여는 클릭이고 change는 항목을 고른 시점이라, 그 사이에 목록을 보고 고르는 시간이 통째로 들어가기 때문이다.

네이티브 <select>는 팝업이 OS 영역에 있어서 "옵션 위에서 눌린 순간"을 웹에서 잡을 수 없다. <option>에 핸들러를 붙여도 발화하지 않고, document에 캡처 리스너를 걸어도 SELECT만 잡힐 뿐 OPTION은 잡히지 않았다. 지연 구간을 직접 계측할 방법이 없었다.

좀 더 명확하게 하기 위해서 측정이 필요하다고 느꼈다. 측정을 위해서 크게 두 가지 툴을 AI가 추천을 해주었는데 electron의 chromium 내장되어 dev tool을 이용하는 것과 리액트에서 지원하는 dev tool을 추천해주었다. 여러가지를 종합해서 확인할 수 있는 것이 chromium dev tool이어서 이것을 사용했다.

스크린샷 2026-09-19 오후 1.01.09.png

렌더링 시간이 문제라고 생각을 하였는데 결과는 달랐다. idle 시간이 전체를 차지하고 있었다. idle 시간은 외부 요소와 관련이 있다고 생각이 들어서 다른 요소들도 확인을 해봤고 아래는 그 테이블표다.

후보 확인 방법 결과
JS 실행 부하 Main 스레드 트랙 비어 있음
네트워크 Network 탭 모든 요청 40ms 이내
Vite dev 서버 선택 시점 요청 유무 신규 요청 없음
IPC 코드 확인 드롭다운 변경 시 호출 없음
CSS transition transition: none !important 변화 없음
setTimeout 전역 함수 패치 후 console.trace 로그 없음
React 상태 전파 change/render 로그 2ms
macOS Tahoe 렉 이슈 CHROME_HEADLESS=1 실행 변화 없음

가장 결정적이었던 건 프로그래밍 방식 측정이다. 사람 손과 팝업을 모두 배제하고 값만 바꿔봤다.

const el = document.querySelector('select');
const setter = Object.getOwnPropertyDescriptor(
  HTMLSelectElement.prototype, 'value'
).set;
const t0 = performance.now();
setter.call(el, 'sqlite');
el.dispatchEvent(new Event('change', { bubbles: true }));
requestAnimationFrame(() => requestAnimationFrame(() =>
  console.log('paint:', Math.round(performance.now() - t0), 'ms')
));

8ms. 화면 반영까지 포함한 수치다. 값 변경부터 페인트까지 과정을 확인해보면 아무런 상관이 없었다.


https://chromium.googlesource.com/chromium/src/+/335d78a0e0299bda3465cb7e303b79e043f680da

mac 환경에서 OS에서 제공하는 UI를 사용하는데 닫힘 애니메이션이 UI 스레드를 블록하고 그동안 이벤트가 동작한다는 내용이다. 수정되었고 지연 시간도 300ms 정도인데 시간은 다르지만 상황은 비슷했다. 다만 2017년에 수정된 300ms짜리 이슈 하나가 2026년 3초 지연의 단서가 되긴 어렵다.


https://developer.mozilla.org/en-US/docs/Web/CSS/appearance

macOS에서 <select> 팝업은 NSMenu로 구현되어 있는데 이것은 운영체제에서 지원하는 것이기 때문에 떠 있는 동안 지연이 발생하는 걸로 가정을 했다. 그래서 base-select 속성을 주면 지연이 사라져야 하지만 체감상 변화는 없었다.