[{"data":1,"prerenderedAt":174},["ShallowReactive",2],{"qa-\u002Fjavascript\u002Fasync\u002Fevent-loop":3},{"page":4,"siblings":165,"blog":171},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":12,"path":20,"questions":21,"related":156,"seo":157,"seoDescription":158,"stem":159,"subtopic":160,"topic":161,"topicSlug":162,"updated":163,"__hash__":164},"qa\u002Fjavascript\u002Fasync\u002Fevent-loop.md","Event Loop",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"hard","md","JavaScript","javascript",{},true,"\u002Fjavascript\u002Fasync\u002Fevent-loop",[22,27,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152],{"id":23,"difficulty":24,"q":25,"a":26},"what-is-event-loop","medium","What is the event loop?","JavaScript runs on a **single thread** — one call stack, one thing at a time.\nThe event loop is the coordinator that lets that single thread *appear*\nconcurrent: it repeatedly checks \"is the call stack empty?\" and, when it is,\npulls the next queued callback and pushes it onto the stack to run.\n\nThe pieces involved:\n\n- **Call stack** — the function currently executing.\n- **Web\u002FNode APIs** — timers, network, I\u002FO that run *outside* the engine and\n  hand a callback back when done.\n- **Task & microtask queues** — where those finished callbacks wait.\n\n```js\nwhile (true) {\n  runUntilStackEmpty()   \u002F\u002F execute current synchronous work\n  drainMicrotasks()      \u002F\u002F then ALL queued microtasks\n  if (oneMacrotask) run(oneMacrotask) \u002F\u002F then exactly one macrotask, repeat\n}\n```\n\nSo async code never \"interrupts\" running code — it waits until the stack is\nclear, which is why the event loop is the heart of every \"what's the output\norder?\" interview question.\n",{"id":28,"difficulty":29,"q":30,"a":31},"call-stack","easy","What is the call stack?","The call stack is a **LIFO (last-in, first-out)** structure that tracks where\nthe program is in its execution. Calling a function **pushes** a frame (its\nlocal variables and return address); returning **pops** it. JavaScript has\nexactly one call stack, so it executes one frame at a time.\n\n```js\nfunction a() { b() }\nfunction b() { c() }\nfunction c() { throw new Error('boom') }\na()\n\u002F\u002F Stack at the throw (top first): c -> b -> a -> (global)\n\u002F\u002F That ordering is literally what a stack trace prints.\n```\n\nTwo consequences worth naming in an interview: deep\u002Finfinite recursion\noverflows the stack (`Maximum call stack size exceeded`), and because there's\nonly one stack, any long synchronous function **blocks** everything else until\nit returns.\n",{"id":33,"difficulty":14,"q":34,"a":35},"macro-micro","What is the difference between the macrotask and microtask queues?","There are two priority levels of queued work, and the event loop treats them\nvery differently:\n\n- **Macrotasks** (a.k.a. \"tasks\"): `setTimeout`, `setInterval`,\n  `setImmediate`, I\u002FO callbacks, UI events. The loop runs **one** per\n  iteration.\n- **Microtasks**: promise `.then`\u002F`catch`\u002F`finally` callbacks,\n  `queueMicrotask`, `await` continuations, `MutationObserver`.\n\nThe critical rule: after each macrotask (and after the initial synchronous\nscript), the engine **drains the entire microtask queue** — including any\nmicrotasks those microtasks schedule — *before* picking up the next macrotask\nor rendering.\n\n```js\nsetTimeout(() => console.log('macro'), 0)\nPromise.resolve()\n  .then(() => console.log('micro 1'))\n  .then(() => console.log('micro 2'))\n\u002F\u002F micro 1, micro 2, macro\n\u002F\u002F Both microtasks finish before the timer, even with a 0ms delay.\n```\n\nThat \"microtasks always win\" behavior is why a resolved promise consistently\nbeats a `setTimeout(0)`.\n",{"id":37,"difficulty":14,"q":38,"a":39},"ordering","What is the output order of this snippet?","```js\nconsole.log('A')\nsetTimeout(() => console.log('B'))\nPromise.resolve().then(() => console.log('C'))\nconsole.log('D')\n```\n\n**Output: `A D C B`.** Walk it through the way you would on a whiteboard:\n\n1. `console.log('A')` — synchronous, runs now -> **A**.\n2. `setTimeout(...)` — hands the callback to the timer API; it'll be queued as\n   a **macrotask**. Nothing prints yet.\n3. `Promise.resolve().then(...)` — schedules its callback as a **microtask**.\n   Nothing prints yet.\n4. `console.log('D')` — synchronous -> **D**.\n5. Script finishes, stack is empty -> drain **microtasks** -> **C**.\n6. Next macrotask runs -> **B**.\n\nThe takeaway: all synchronous code first, then every microtask, then the next\nmacrotask.\n",{"id":41,"difficulty":24,"q":42,"a":43},"blocking","What happens if you run a long synchronous loop?","It **blocks the single thread**. While the loop runs the call stack never\nempties, so the event loop can't pull anything from the queues: timers don't\nfire on time, promise callbacks wait, clicks\u002Fscroll feel frozen, and the page\ncan't repaint (the dreaded \"page unresponsive\").\n\n```js\nconst end = Date.now() + 3000\nwhile (Date.now() \u003C end) {} \u002F\u002F freezes the tab for 3 full seconds\nconsole.log('finally free')\n```\n\nFixes: break the work into chunks that yield to the loop (`setTimeout`,\n`requestIdleCallback`), or move CPU-heavy work off the main thread into a **Web\nWorker** (browser) \u002F **Worker thread** (Node) so the UI stays responsive.\n",{"id":45,"difficulty":14,"q":46,"a":47},"starvation","Can microtasks starve the event loop?","Yes. Because the engine drains the **whole** microtask queue before moving on,\na microtask that keeps scheduling more microtasks creates a queue that never\nempties — so macrotasks (timers, I\u002FO) and rendering are postponed\nindefinitely. The tab effectively hangs even though \"async\" code is running.\n\n```js\nfunction loop() {\n  queueMicrotask(loop) \u002F\u002F re-queues itself forever -> macrotasks never run\n}\nloop()\nsetTimeout(() => console.log('I will never print'), 0)\n```\n\nTo avoid starvation, yield to the macrotask queue for repeated\u002Flong work\n(`setTimeout`, `MessageChannel`, or `await` a real async boundary) so the loop\ngets a chance to run timers and paint frames between chunks.\n",{"id":49,"difficulty":24,"q":50,"a":51},"queuemicrotask","What is queueMicrotask?","`queueMicrotask(fn)` schedules a callback to run as a **microtask** — after the\ncurrent synchronous code finishes but before the next macrotask. It's the direct\nway to queue a microtask without abusing `Promise.resolve().then()`.\n\n```js\nconsole.log('sync')\nqueueMicrotask(() => console.log('microtask'))\nconsole.log('sync 2')\n\u002F\u002F sync, sync 2, microtask\n```\n\nUse it to defer work to \"just after this task\" while still beating timers — e.g.\nbatching DOM reads or ensuring a callback runs after the current call stack\nunwinds but ASAP.\n",{"id":53,"difficulty":14,"q":54,"a":55},"raf","How does requestAnimationFrame fit into the event loop?","`requestAnimationFrame(cb)` schedules `cb` to run **right before the next\nrepaint**, typically ~60 times per second. It's neither a macrotask nor a\nmicrotask — the browser runs rAF callbacks in a dedicated step of the rendering\npipeline, just before layout\u002Fpaint.\n\n```js\nrequestAnimationFrame(() => {\n  el.style.transform = `translateX(${x}px)` \u002F\u002F applied in sync with the frame\n})\n```\n\nUse it for animations and visual updates so they're synced to the display\nrefresh (no tearing, no wasted frames). Unlike `setTimeout`, it pauses in\nbackground tabs.\n",{"id":57,"difficulty":24,"q":58,"a":59},"settimeout-clamp","Is setTimeout(fn, 0) really zero milliseconds?","No. `setTimeout(fn, 0)` means \"run as soon as possible **as a macrotask**,\" not\ninstantly. The HTML spec also **clamps** nested timeouts to a minimum (~4ms after\n5 levels of nesting), and the callback still waits for the stack to clear and all\nmicrotasks to drain.\n\n```js\nsetTimeout(() => console.log('timer'), 0)\nPromise.resolve().then(() => console.log('microtask'))\n\u002F\u002F microtask runs first — the \"0ms\" timer is still a macrotask\n```\n\nSo `setTimeout(0)` is \"defer to the next task,\" useful for yielding, but never a\nprecise or immediate timer.\n",{"id":61,"difficulty":14,"q":62,"a":63},"node-vs-browser","How does the event loop differ between Node.js and the browser?","The core idea (stack + queues + microtask draining) is the same, but the\nimplementations differ:\n\n- The **browser** loop is defined by the HTML spec and integrates with\n  **rendering** (rAF, paint, layout).\n- **Node** uses **libuv** with distinct **phases** (timers, pending callbacks,\n  poll, check, close) and adds `process.nextTick` and `setImmediate`, with no\n  rendering step.\n\n```js\n\u002F\u002F Node-only ordering nuance:\nsetImmediate(() => console.log('immediate'))\nsetTimeout(() => console.log('timeout'), 0)\nprocess.nextTick(() => console.log('nextTick'))\n\u002F\u002F nextTick runs before both; immediate vs timeout order can vary\n```\n\nMicrotasks (promises) drain between phases\u002Ftasks in both environments.\n",{"id":65,"difficulty":14,"q":66,"a":67},"nexttick","What is process.nextTick in Node and how does it differ from microtasks?","`process.nextTick(fn)` queues `fn` to run **after the current operation\ncompletes**, before the event loop continues — and crucially **before** the\nPromise microtask queue. So Node effectively has two micro-queues, with\n`nextTick` having higher priority.\n\n```js\nPromise.resolve().then(() => console.log('promise'))\nprocess.nextTick(() => console.log('nextTick'))\n\u002F\u002F nextTick, promise\n```\n\nBecause it preempts everything, recursively scheduling `nextTick` can **starve**\nthe loop entirely. Prefer `queueMicrotask`\u002Fpromises unless you specifically need\nits priority.\n",{"id":69,"difficulty":14,"q":70,"a":71},"await-puzzle","What is the output order of this async\u002Fawait snippet?","```js\nconsole.log('1')\nasync function f() {\n  console.log('2')\n  await null\n  console.log('3')\n}\nf()\nconsole.log('4')\n\u002F\u002F Output: 1, 2, 4, 3\n```\n\n`f()` runs synchronously up to the `await` (logs **2**). `await` suspends the\nfunction and schedules the rest (`console.log('3')`) as a **microtask**, so\ncontrol returns to the caller and **4** logs. After the synchronous code, the\nmicrotask runs -> **3**. The body before the first `await` is synchronous; only\nwhat follows is deferred.\n",{"id":73,"difficulty":14,"q":74,"a":75},"rendering-tasks","When does the browser render relative to tasks and microtasks?","The browser tries to render at most **once per frame** (~16.7ms at 60fps), and it\ndoes so **after** the current macrotask **and** its full microtask queue have\ncompleted — never in the middle of a task.\n\n```\nmacrotask -> drain microtasks -> (rAF callbacks) -> style\u002Flayout\u002Fpaint -> next macrotask\n```\n\nConsequence: synchronous DOM changes within one task aren't painted individually\n— only the final state shows. And a long task blocks rendering entirely, which is\nwhy long synchronous work freezes the page.\n",{"id":77,"difficulty":14,"q":78,"a":79},"await-scheduling","How does await schedule the rest of an async function?","`await x` pauses the function and registers the **remaining code as a\ncontinuation** (a `.then` callback on `x`), which runs as a **microtask** once\n`x` settles. The async function is essentially rewritten into promise\ncontinuations by the engine.\n\n```js\nasync function g() {\n  const a = await fetchA() \u002F\u002F everything below becomes a microtask continuation\n  const b = await fetchB() \u002F\u002F ...and so does this, after a resolves\n  return a + b\n}\n```\n\nSo each `await` introduces a microtask boundary. This is why code after `await`\nalways runs after the current synchronous task, never inline.\n",{"id":81,"difficulty":24,"q":82,"a":83},"settimeout-recursion","What is the difference between setInterval and recursive setTimeout?","`setInterval` queues the callback every N ms **regardless of how long it takes**\n— if the callback is slow, executions can pile up or overlap conceptually.\n**Recursive `setTimeout`** schedules the next run only **after** the current one\nfinishes, guaranteeing a gap.\n\n```js\n\u002F\u002F guarantees ≥1s between completions\nfunction poll() {\n  doWork()\n  setTimeout(poll, 1000)\n}\nsetTimeout(poll, 1000)\n```\n\nRecursive `setTimeout` is preferred for variable-duration work and for adapting\nthe delay dynamically; `setInterval` is fine for short, fixed-cadence ticks.\n",{"id":85,"difficulty":14,"q":86,"a":87},"promise-chain-order","How are chained .then callbacks ordered against each other?","Each `.then` schedules its callback as a **separate microtask**, queued only when\nthe previous link resolves. So two independent chains **interleave** one\nmicrotask at a time.\n\n```js\nPromise.resolve().then(() => console.log('A1')).then(() => console.log('A2'))\nPromise.resolve().then(() => console.log('B1')).then(() => console.log('B2'))\n\u002F\u002F A1, B1, A2, B2\n```\n\n`A1` and `B1` are queued first; running `A1` queues `A2`, running `B1` queues\n`B2`. The engine drains the queue in FIFO order, producing the interleaving.\n",{"id":89,"difficulty":24,"q":90,"a":91},"yield-main-thread","How do you yield to the event loop to keep the UI responsive?","Break long synchronous work into chunks and **schedule the next chunk as a\nmacrotask** so the loop can run timers, handle input, and paint in between.\n\n```js\nfunction processChunk(i) {\n  const end = Math.min(i + 1000, data.length)\n  for (; i \u003C end; i++) handle(data[i])\n  if (i \u003C data.length) setTimeout(() => processChunk(i), 0) \u002F\u002F yield\n}\nprocessChunk(0)\n```\n\nModern options include `scheduler.yield()`, `MessageChannel`, or\n`requestIdleCallback`. For pure CPU work, a **Web Worker** keeps the main thread\nfree entirely.\n",{"id":93,"difficulty":14,"q":94,"a":95},"node-phases","What are the phases of the Node.js event loop?","libuv runs the loop through ordered phases, each with its own callback queue:\n\n1. **timers** — `setTimeout`\u002F`setInterval` callbacks.\n2. **pending callbacks** — deferred I\u002FO callbacks.\n3. **poll** — retrieve new I\u002FO events; execute I\u002FO callbacks.\n4. **check** — `setImmediate` callbacks.\n5. **close** — `close` event callbacks.\n\nBetween **every** phase, Node drains `process.nextTick` and the microtask\n(promise) queues. This phased structure is why `setImmediate` (check) and\n`setTimeout(0)` (timers) can fire in different orders depending on context.\n",{"id":97,"difficulty":14,"q":98,"a":99},"setimmediate","What is the difference between setImmediate and setTimeout(0) in Node?","`setImmediate` runs in the **check** phase, after the **poll** phase, while\n`setTimeout(0)` runs in the **timers** phase at the start of the next loop. Inside\nan **I\u002FO callback**, `setImmediate` is deterministically first; at the top level\ntheir order is non-deterministic.\n\n```js\nconst fs = require('fs')\nfs.readFile(__filename, () => {\n  setTimeout(() => console.log('timeout'), 0)\n  setImmediate(() => console.log('immediate'))\n  \u002F\u002F inside I\u002FO: \"immediate\" always logs first\n})\n```\n\nRule: to run \"after the current I\u002FO, ASAP,\" use `setImmediate`.\n",{"id":101,"difficulty":24,"q":102,"a":103},"promise-executor-sync","Does the Promise executor function run synchronously?","Yes. The function you pass to `new Promise((resolve, reject) => {...})` runs\n**synchronously, immediately**, as part of constructing the promise. Only the\n`.then`\u002F`.catch` **callbacks** are asynchronous (microtasks).\n\n```js\nconsole.log('start')\nnew Promise(resolve => {\n  console.log('executor')   \u002F\u002F runs now, synchronously\n  resolve()\n}).then(() => console.log('then'))\nconsole.log('end')\n\u002F\u002F start, executor, end, then\n```\n\nA common misconception is that everything about a promise is async — the executor\nbody is not.\n",{"id":105,"difficulty":24,"q":106,"a":107},"await-nonpromise","What happens when you await a non-promise value?","`await` wraps any non-promise in `Promise.resolve(value)`, so the value comes back\nas-is — but the function **still suspends for one microtask tick**. So even\n`await 5` defers the rest of the function.\n\n```js\nasync function f() {\n  console.log('before')\n  await 5            \u002F\u002F not a promise, but still yields a microtask\n  console.log('after')\n}\nf()\nconsole.log('sync')\n\u002F\u002F before, sync, after\n```\n\nSo `await` always introduces an async boundary, even for plain values — handy to\nknow for ordering puzzles.\n",{"id":109,"difficulty":24,"q":110,"a":111},"async-not-multithread","Does asynchronous code mean JavaScript is multithreaded?","No. JavaScript runs on a **single thread**; async just means work is **scheduled**\nto run later rather than blocking. The *waiting* (timers, network, file I\u002FO)\nhappens outside the JS engine (in the browser\u002FOS\u002Flibuv), but your callbacks all\nrun one-at-a-time on the same thread.\n\n```js\nsetTimeout(() => console.log('later'), 1000) \u002F\u002F the timer is handled elsewhere;\n\u002F\u002F the callback still runs on the single JS thread when the stack is free\n```\n\nTrue parallelism in JS requires **Web Workers** \u002F **worker threads**, which run\nseparate threads communicating via messages.\n",{"id":113,"difficulty":29,"q":114,"a":115},"why-single-thread","Why is JavaScript single-threaded?","JavaScript was designed single-threaded to keep the **DOM model simple** — if\nmultiple threads could mutate the DOM concurrently, you'd need locks everywhere\nand face race conditions on every UI update. A single thread plus the event loop\ngives concurrency (handling many things) without the complexity of parallelism.\n\n```js\n\u002F\u002F no data races: only one piece of JS touches `count` at a time\nlet count = 0\nbutton.onclick = () => count++\n```\n\nThe trade-off is that CPU-heavy work blocks everything — solved by offloading to\nWeb Workers when needed.\n",{"id":117,"difficulty":29,"q":118,"a":119},"callback-queue","What is the callback (task) queue?","The callback queue (a.k.a. task\u002Fmacrotask queue) holds callbacks that are\n**ready to run** but waiting for the call stack to clear — completed timers,\nresolved I\u002FO, dispatched events. The event loop moves one of them onto the stack\neach iteration.\n\n```js\nbutton.addEventListener('click', handler) \u002F\u002F handler is queued when clicked\nsetTimeout(cb, 100)                        \u002F\u002F cb is queued ~100ms later\n```\n\nIt's strictly FIFO per task source, and the loop only pulls from it when the\nstack is empty and microtasks are drained.\n",{"id":121,"difficulty":14,"q":122,"a":123},"nested-timeout-order","What is the order of nested setTimeout and promise callbacks?","```js\nsetTimeout(() => {\n  console.log('timeout 1')\n  Promise.resolve().then(() => console.log('promise in timeout'))\n}, 0)\nsetTimeout(() => console.log('timeout 2'), 0)\n\u002F\u002F timeout 1, promise in timeout, timeout 2\n```\n\nEach macrotask is followed by a **full microtask drain** before the next\nmacrotask. So after \"timeout 1\" runs, its queued promise microtask executes\n**before** \"timeout 2\". This \"microtasks between every macrotask\" rule is the key\nto these puzzles.\n",{"id":125,"difficulty":14,"q":126,"a":127},"microtask-checkpoint","What is a microtask checkpoint?","A microtask checkpoint is the point where the engine **drains the entire\nmicrotask queue**. It happens after the current macrotask completes (the stack\nempties) and also after certain operations like a callback returning. All pending\nmicrotasks — and any they schedule — run to completion before the next macrotask\nor render.\n\n```js\n\u002F\u002F everything queued via .then\u002FqueueMicrotask runs at the next checkpoint,\n\u002F\u002F before any setTimeout callback\n```\n\nUnderstanding checkpoints explains why microtasks always \"win\" and why they can\nstarve the loop if they keep scheduling more.\n",{"id":129,"difficulty":14,"q":130,"a":131},"ordering-puzzle2","Trace the output of mixed sync, await, promise and setTimeout.","```js\nconsole.log('A')\nsetTimeout(() => console.log('B'), 0)\nPromise.resolve().then(() => console.log('C'))\n;(async () => {\n  console.log('D')\n  await null\n  console.log('E')\n})()\nconsole.log('F')\n\u002F\u002F A, D, F, C, E, B\n```\n\nSync first: **A**, then the async IIFE runs to its `await` -> **D**, then **F**.\nMicrotasks drain next: **C** (queued before the await continuation), then **E**.\nFinally the macrotask: **B**. Order of microtasks follows the order they were\nqueued.\n",{"id":133,"difficulty":24,"q":134,"a":135},"input-responsiveness","How do long tasks hurt responsiveness (INP)?","A \"long task\" (>50ms of synchronous work) monopolizes the single thread, so the\nevent loop can't process the click\u002Fkeypress callback or repaint — the user\nperceives lag. This directly worsens the **INP (Interaction to Next Paint)**\nmetric.\n\n```js\nbutton.onclick = () => {\n  heavyCompute() \u002F\u002F blocks -> the visual response is delayed\n}\n```\n\nFixes: break work into chunks that yield, defer non-urgent work\n(`requestIdleCallback`), debounce, or move computation to a Web Worker so input\nhandling and painting stay snappy.\n",{"id":137,"difficulty":24,"q":138,"a":139},"raf-vs-timeout-animation","Why use requestAnimationFrame instead of setTimeout for animation?","`requestAnimationFrame` runs **in sync with the display refresh** (right before\npaint) and **pauses in background tabs**, so animations are smooth and don't waste\nCPU\u002Fbattery. `setTimeout` fires on an arbitrary schedule unrelated to the frame,\ncausing dropped or doubled frames and jank.\n\n```js\nfunction animate() {\n  move()\n  requestAnimationFrame(animate) \u002F\u002F one update per frame, perfectly timed\n}\nrequestAnimationFrame(animate)\n```\n\nrAF also self-throttles to the screen's refresh rate, whereas a fixed\n`setTimeout(16)` drifts and can't adapt to 120Hz displays.\n",{"id":141,"difficulty":24,"q":142,"a":143},"one-macrotask-per-tick","Why does the loop process only one macrotask per iteration?","Running one macrotask then draining microtasks (and giving rendering a chance)\nkeeps the system **responsive and fair**: it prevents a flood of queued tasks\nfrom blocking input handling and painting, and ensures microtask-based work\n(promises) completes promptly between tasks.\n\n```\n[1 macrotask] -> [all microtasks] -> [maybe render] -> [1 macrotask] -> ...\n```\n\nIf the loop drained the whole macrotask queue at once, a burst of timers\u002Fevents\ncould lock out rendering and user input until they all finished.\n",{"id":145,"difficulty":29,"q":146,"a":147},"sync-vs-async-diff","What is the difference between synchronous and asynchronous code?","**Synchronous** code runs top-to-bottom, each statement **blocking** until it\nfinishes. **Asynchronous** code starts an operation and **continues without\nwaiting**, handling the result later via a callback\u002Fpromise — so the thread isn't\nblocked.\n\n```js\nconst data = readFileSync('f.txt') \u002F\u002F sync: blocks here until done\nreadFile('f.txt', (e, data) => {}) \u002F\u002F async: returns immediately, callback later\n```\n\nAsync is essential in single-threaded JS so that slow I\u002FO (network, disk) doesn't\nfreeze the UI — the event loop schedules the continuation when the result is\nready.\n",{"id":149,"difficulty":14,"q":150,"a":151},"workers-offload","How do Web Workers relate to the event loop?","A Web Worker runs JavaScript on a **separate thread with its own event loop**, so\nCPU-heavy work there doesn't block the main thread's loop (and thus the UI). They\ncommunicate via `postMessage`, which queues a **message-event** (macrotask) on\nthe receiving side.\n\n```js\nconst worker = new Worker('heavy.js')\nworker.postMessage(bigData)\nworker.onmessage = e => render(e.data) \u002F\u002F runs on main thread when free\n```\n\nWorkers don't share memory by default (except `SharedArrayBuffer`), avoiding data\nraces. Use them to keep the main loop free for input and rendering.\n",{"id":153,"difficulty":24,"q":154,"a":155},"defer-with-tasks","How can you defer work to the next tick using the event loop?","To run something **after** the current synchronous code without blocking, schedule\nit on a queue. The choice of queue controls priority:\n\n```js\nqueueMicrotask(fn)        \u002F\u002F ASAP: before the next render\u002Fmacrotask\nPromise.resolve().then(fn) \u002F\u002F also a microtask\nsetTimeout(fn, 0)          \u002F\u002F next macrotask (after microtasks + maybe a paint)\nrequestAnimationFrame(fn)  \u002F\u002F before the next paint\n```\n\nPick a **microtask** when the deferral must beat rendering\u002Ftimers, and a\n**macrotask** when you want to yield the thread (let input\u002Fpaint happen) before\ncontinuing.\n",null,{"description":11},"JavaScript event loop interview questions — the call stack, task and microtask queues, and how asynchronous code is scheduled.","javascript\u002Fasync\u002Fevent-loop","The Event Loop","Asynchronous JavaScript","async","2026-06-17","v5VF_8JManXxxPa5kLV8PcWEglG8nn9bwl29BN9yPxg",[166,170],{"subtopic":167,"path":168,"order":169},"Promises & async\u002Fawait","\u002Fjavascript\u002Fasync\u002Fpromises",1,{"subtopic":160,"path":20,"order":12},{"path":172,"title":173},"\u002Fblog\u002Fjavascript-event-loop-explained","The JavaScript Event Loop — How Asynchronous Code Really Works",1781808675900]