줄 1 / 45
0 오타
1import { useState } from "react";
2 3// JavaScript runs ONE thing at a time (it is single-threaded). When async work finishes, 4// its callback does not run immediately — it waits in a QUEUE. There are two queues, and 5// they do NOT have equal priority: 6// 7// • microtasks — Promise .then / queueMicrotask. The engine drains ALL of these first.🗣 치면서 / 다 치고 — 소리내서 말해
JavaScript is single-threaded: async callbacks wait in queues. Microtasks (promises) are fully drained before any macrotask (setTimeout). So a promise scheduled LATER still runs before a 0ms timer scheduled earlier. Run it and read the order.
Promise.resolve().then(() => out.push("3 microtask"))A resolved promise's callback is a microtask — it runs after the synchronous code but before any timer.
setTimeout(() => out.push("4 macrotask"), 0)Even a zero-millisecond timeout is a macrotask, so it waits until every microtask is drained — that's why three prints before four.
⚖️ 트레이드오프도 말해봐
- A resolved promise's callback runs on the microtask queue, which the event loop fully drains after the current synchronous frame but BEFORE rendering, I/O, or any macrotask, whereas setTimeout(0) is a macrotask clamped to a ~4ms minimum and queued behind already-pending timers and rendering — so a promise wins precisely because microtasks have strictly higher priority than the timer phase.
- The cost of that priority is starvation: because the loop empties the entire microtask queue before yielding, a chain of promises that keep enqueuing more microtasks can block rendering and starve I/O indefinitely, which is exactly the failure mode setTimeout(0) avoids by surrendering control back to the loop after one task.
- Reach for queueMicrotask/Promise.resolve().then() when you need to defer work but still land before the next paint — e.g. batching state mutations or guaranteeing a callback runs after the current call stack unwinds without ever yielding to the browser.
- Use setTimeout(0) (or better, requestAnimationFrame for visual work, or MessageChannel to dodge the 4ms clamp) precisely when you WANT to yield — to let the browser paint, process input, or break up a long task so the main thread stays responsive; choosing a microtask there is the bug, not the optimization.