--- id: wiki-2026-0508-main-thread title: Main Thread category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Browser Main Thread, UI Thread, JS Main Thread, Event Loop Thread] duplicate_of: none source_trust_level: A confidence_score: 0.94 verification_status: applied tags: [web-performance, browser, event-loop, inp, web-worker, rendering, javascript] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: { language: javascript|typescript, framework: browser|web-worker } --- # Main Thread > 한 줄: 브라우저에서 JS 실행·DOM 파싱·layout·paint·이벤트 처리가 모두 도는 단일 스레드 — 막히면 INP·반응성 즉사. ## 핵심 - **Single-threaded**: JS는 main thread 위 event loop. 한 task가 길면 모두 정지. - **Long task**: ≥50ms 작업 → INP 악화. Core Web Vitals 핵심 지표. - **Pipeline**: parse HTML → CSSOM → JS 실행 → layout → paint → composite. 매 frame 16.7ms (60fps) 안에 끝나야. - **분리 가능 작업**: heavy compute (CSV parse, image proc, crypto, ML) → Web Worker. DOM은 worker 불가. - **도구**: Chrome DevTools Performance, `PerformanceObserver('longtask')`, `scheduler.yield()` (2025+). ## 결정 기준 | 작업 | 처리 | |---|---| | DOM 조작 | main thread (필수) — batch + virtual DOM | | JSON parse < 1MB | main, OK | | JSON parse > 5MB | Web Worker | | 이미지 리사이즈 | OffscreenCanvas + Worker | | ML 추론 | Worker + WebGPU/WASM | | 큰 list 렌더 | virtualization (react-window, TanStack Virtual) | | 긴 루프 | `scheduler.yield()` 또는 chunked + `setTimeout(0)` | | 우선순위 제어 | `scheduler.postTask({priority:'background'})` | ## 💻 패턴 ### Long task 측정 ```js new PerformanceObserver((list) => { for (const e of list.getEntries()) console.warn("longtask", e.duration, e); }).observe({ type: "longtask", buffered: true }); ``` ### Yield to main thread (2025+ standard) ```js async function processItems(items) { for (const item of items) { doWork(item); if (navigator.scheduling?.isInputPending() || performance.now() % 50 < 1) { await scheduler.yield(); // 또는 await new Promise(r => setTimeout(r, 0)) } } } ``` ### Web Worker (module) ```js // main.js const worker = new Worker(new URL("./heavy.worker.js", import.meta.url), { type: "module" }); worker.postMessage({ csv: largeText }); worker.onmessage = (e) => render(e.data); // heavy.worker.js import Papa from "papaparse"; self.onmessage = ({ data }) => { const parsed = Papa.parse(data.csv, { header: true }); self.postMessage(parsed.data); }; ``` ### OffscreenCanvas (이미지/그래픽 워커화) ```js const canvas = document.querySelector("canvas").transferControlToOffscreen(); const w = new Worker("draw.worker.js"); w.postMessage({ canvas }, [canvas]); // transfer ``` ### Scheduler API 우선순위 ```js scheduler.postTask(() => analytics.flush(), { priority: "background" }); scheduler.postTask(() => updateBadge(), { priority: "user-blocking" }); ``` ### React 18+ transitions (cooperative) ```jsx import { useTransition, useDeferredValue } from "react"; const [isPending, startTransition] = useTransition(); const onChange = (v) => { setQuery(v); // urgent startTransition(() => setResults(filter(v))); // non-urgent }; ``` ### Long task 분할 (chunk) ```js function chunked(items, fn, chunkSize = 100) { return new Promise((resolve) => { let i = 0; function step() { const end = Math.min(i + chunkSize, items.length); for (; i < end; i++) fn(items[i]); if (i < items.length) setTimeout(step, 0); else resolve(); } step(); }); } ``` ## 🔗 Graph - 상위: [[Web-Performance]] · [[Browser-Internals]] · [[Event-Loop]] - 관련: [[Web-Worker]] · [[Service-Worker]] · [[OffscreenCanvas]] · [[INP]] · [[Core Web Vitals Optimization (INP, LCP 개선)|Core-Web-Vitals]] · [[React-Concurrent]] · [[Scheduler-API]] - 도구: [[Lighthouse]] ## 🤖 LLM 활용 - DevTools flame chart를 LLM에 붙여 "어떤 long task가 INP를 망치는지" 해석 요청. - 코드 리뷰 prompt: "이 함수가 main thread를 블록할 가능성 분석". ## ❌ 안티패턴 - **`while(true)` 폴링** — 메인 스레드 점유. requestAnimationFrame/setInterval/이벤트. - **거대 JSON sync parse** — Worker로 이동, streaming JSON (oboe, JSON.parseAsync 제안 등). - **DOM 조작을 루프 안에서 N번** — DocumentFragment/배치 + IntersectionObserver. - **무거운 라이브러리 main bundle** — code split, dynamic import. - **Worker 남용** — 작은 작업은 postMessage 오버헤드가 손해. 임계값 측정. - **`alert/confirm/prompt`** — modal sync block. 커스텀 dialog로 대체. ## 🧪 검증 / 중복 - 중복: [[Event-Loop]], [[Web-Worker]] 별도 — 본 문서는 main thread 관점 허브. - 검증: Lighthouse INP, RUM (web-vitals lib), Chrome DevTools "Performance" 탭 long tasks bar. ## 🕓 Changelog - 2026-05-08 | Phase 1 — 자동 시드. - 2026-05-10 | Manual cleanup — scheduler.yield, Worker, OffscreenCanvas, React transition 패턴 정리, INP 결정 기준 추가.