[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"playground-weekly-javascript-event-loop":32},[4,20],{"id":5,"slug":6,"name":7,"tagline":8,"description":9,"accentFrom":10,"accentTo":11,"icon":12,"defaultLocale":13,"locales":14,"features":16,"position":19},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Build. Learn. Ship.","Practical courses, engineering-grade articles and open-source tools for people who ship.","violet-500","cyan-400","◇","en",[13,15],"fa",{"courses":17,"paths":17,"articles":17,"exams":18,"flashcards":18,"packages":17,"community":17,"certificates":17,"teams":17,"commerce":17},true,false,0,{"id":21,"slug":22,"name":23,"tagline":24,"description":25,"accentFrom":26,"accentTo":10,"icon":27,"defaultLocale":13,"locales":28,"features":30,"position":31},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Structured paths, listening drills and spaced repetition that actually sticks.","amber-400","⌘",[13,15,29],"es",{"courses":17,"paths":17,"articles":18,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":17},2,{"slug":33,"title":34,"summary":35,"html":36,"css":37,"js":38,"config":39,"doc":41},"weekly-javascript-event-loop","the JavaScript event loop",null,"\u003Cdiv class=\"wrap\">\n    \u003Ch1>⏱️ The event loop, one queue at a time\u003C\u002Fh1>\n    \u003Cp class=\"sub\">\n      Queue a mix of \u003Cb>sync\u003C\u002Fb>, \u003Cb>microtask\u003C\u002Fb> (\u003Ccode>Promise.then\u003C\u002Fcode>), and\n      \u003Cb>macrotask\u003C\u002Fb> (\u003Ccode>setTimeout\u003C\u002Fcode>) work, then hit Run. Watch the call\n      stack empty first, then \u003Ci>every\u003C\u002Fi> microtask drain, then one macrotask —\n      exactly the order the real engine uses.\n    \u003C\u002Fp>\n\n    \u003Cdiv class=\"panel\">\n      \u003Cdiv class=\"add-row\">\n        \u003Cspan class=\"lbl\">queue work\u003C\u002Fspan>\n        \u003Cbutton data-add=\"sync\">+ sync log\u003C\u002Fbutton>\n        \u003Cbutton data-add=\"micro\">+ microtask (.then)\u003C\u002Fbutton>\n        \u003Cbutton data-add=\"macro\">+ macrotask (setTimeout)\u003C\u002Fbutton>\n      \u003C\u002Fdiv>\n\n      \u003Cdiv class=\"run-row\">\n        \u003Cbutton id=\"run\" class=\"primary\">▶ Run\u003C\u002Fbutton>\n        \u003Cbutton id=\"reset\" class=\"ghost\">Reset\u003C\u002Fbutton>\n        \u003Cbutton id=\"preset\" class=\"ghost\">Load classic example\u003C\u002Fbutton>\n      \u003C\u002Fdiv>\n\n      \u003Cdiv class=\"lanes\">\n        \u003Cdiv class=\"lane\">\n          \u003Ch2>Call stack \u003Cspan id=\"stackTag\">\u003C\u002Fspan>\u003C\u002Fh2>\n          \u003Cdiv class=\"items\" id=\"stackItems\">\u003Cspan class=\"empty\">empty\u003C\u002Fspan>\u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"lane\">\n          \u003Ch2>Microtask queue \u003Cspan id=\"microTag\">\u003C\u002Fspan>\u003C\u002Fh2>\n          \u003Cdiv class=\"items\" id=\"microItems\">\u003Cspan class=\"empty\">empty\u003C\u002Fspan>\u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"lane\">\n          \u003Ch2>Macrotask queue \u003Cspan id=\"macroTag\">\u003C\u002Fspan>\u003C\u002Fh2>\n          \u003Cdiv class=\"items\" id=\"macroItems\">\u003Cspan class=\"empty\">empty\u003C\u002Fspan>\u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n\n      \u003Cdiv class=\"log\">\n        \u003Cdiv class=\"lbl\">execution order\u003C\u002Fdiv>\n        \u003Col id=\"logList\">\u003C\u002Fol>\n        \u003Cspan class=\"empty\" id=\"logEmpty\">queue some work above, then hit Run\u003C\u002Fspan>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>",":root {\n    --bg: #0f1115; --panel: #171a21; --sunk: #0b0d12; --ink: #e8ebf2; --muted: #99a1b3;\n    --accent: #6ea8fe; --accent2: #ffb454; --good: #3fb950; --bad: #f85149; --line: #262b36;\n    font-family: ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n  }\n  * { box-sizing: border-box; }\n  body { margin: 0; background: var(--bg); color: var(--ink); min-height: 100vh;\n    display: flex; align-items: center; justify-content: center; padding: 18px; }\n  .wrap { width: 100%; max-width: 680px; }\n  h1 { font-size: 1.15rem; margin: 0 0 2px; }\n  .sub { color: var(--muted); font-size: .85rem; margin: 0 0 14px; line-height: 1.45; }\n  code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }\n  .panel { background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 16px; }\n\n  .controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 12px; }\n  button { font: inherit; font-size: .82rem; font-weight: 600; color: var(--ink);\n    background: var(--sunk); border: 1px solid var(--line); border-radius: 999px;\n    padding: 8px 13px; cursor: pointer; transition: background .15s, border-color .15s, transform .1s; }\n  button:hover { border-color: var(--accent); }\n  button:active { transform: scale(.97); }\n  button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }\n  button.primary { background: var(--accent); color: #0b0d10; border-color: var(--accent); }\n  button.ghost { background: transparent; }\n  button:disabled { opacity: .45; cursor: not-allowed; }\n  .add-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }\n  .add-row .lbl { color: var(--muted); font-size: .72rem; text-transform: uppercase;\n    letter-spacing: .5px; width: 100%; margin-bottom: 2px; }\n  .run-row { display: flex; gap: 8px; margin-top: 10px; border-top: 1px dashed var(--line); padding-top: 12px; }\n\n  .lanes { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; margin-top: 14px; }\n  .lane { background: var(--sunk); border: 1px solid var(--line); border-radius: 10px; padding: 10px; min-height: 150px; }\n  .lane h2 { font-size: .72rem; text-transform: uppercase; letter-spacing: .5px; color: var(--muted);\n    margin: 0 0 8px; display: flex; justify-content: space-between; }\n  .lane h2 .active { color: var(--accent2); }\n  .items { display: flex; flex-direction: column; gap: 6px; }\n  .item { background: var(--panel); border: 1px solid var(--line); border-radius: 8px;\n    padding: 6px 9px; font-size: .8rem; display: flex; justify-content: space-between; gap: 6px;\n    animation: pop .18s ease; }\n  .item.sync { border-color: var(--accent); }\n  .item.micro { border-color: var(--accent2); }\n  .item.macro { border-color: var(--muted); }\n  .item.running { outline: 2px solid var(--good); }\n  @keyframes pop { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }\n\n  .log { margin-top: 12px; background: var(--sunk); border: 1px solid var(--line); border-radius: 10px;\n    padding: 10px 12px; font-size: .82rem; min-height: 44px; }\n  .log .lbl { color: var(--muted); font-size: .72rem; text-transform: uppercase; letter-spacing: .5px; margin-bottom: 6px; }\n  .log ol { margin: 0; padding-left: 18px; }\n  .log li { margin-bottom: 2px; }\n  .log li .tag { color: var(--muted); font-size: .72rem; }\n  .empty { color: var(--muted); font-size: .78rem; font-style: italic; }\n  @media (max-width: 480px) { .lanes { grid-template-columns: 1fr; } }","const $ = (id) => document.getElementById(id);\n  const stackEl = $(\"stackItems\"), microEl = $(\"microItems\"), macroEl = $(\"macroItems\");\n  const logList = $(\"logList\"), logEmpty = $(\"logEmpty\");\n\n  let queued = []; \u002F\u002F work added before Run, in click order (the \"script\")\n  let seq = 0;\n\n  const KIND_LABEL = { sync: \"sync\", micro: \"microtask\", macro: \"macrotask\" };\n\n  function render(list, el, activeId) {\n    el.innerHTML = \"\";\n    if (!list.length) { el.innerHTML = '\u003Cspan class=\"empty\">empty\u003C\u002Fspan>'; return; }\n    for (const it of list) {\n      const div = document.createElement(\"div\");\n      div.className = \"item \" + it.kind + (it.id === activeId ? \" running\" : \"\");\n      div.innerHTML = `\u003Cspan>${it.label}\u003C\u002Fspan>`;\n      el.appendChild(div);\n    }\n  }\n\n  function renderQueuedPreview() {\n    render(queued, stackEl);\n    $(\"stackTag\").textContent = queued.length ? `(${queued.length} queued)` : \"\";\n    render([], microEl); render([], macroEl);\n    $(\"microTag\").textContent = \"\"; $(\"macroTag\").textContent = \"\";\n  }\n\n  function addWork(kind) {\n    seq++;\n    const label = kind === \"sync\" ? `console.log(${seq})`\n      : kind === \"micro\" ? `Promise.then(${seq})`\n      : `setTimeout(${seq})`;\n    queued.push({ id: seq, kind, label });\n    renderQueuedPreview();\n  }\n\n  document.querySelectorAll(\"[data-add]\").forEach((b) =>\n    b.addEventListener(\"click\", () => addWork(b.dataset.add))\n  );\n\n  $(\"preset\").addEventListener(\"click\", () => {\n    queued = []; seq = 0;\n    addWork(\"sync\"); addWork(\"macro\"); addWork(\"micro\"); addWork(\"sync\");\n  });\n\n  $(\"reset\").addEventListener(\"click\", () => {\n    queued = []; seq = 0;\n    renderQueuedPreview();\n    logList.innerHTML = \"\"; logEmpty.style.display = \"block\";\n    $(\"run\").disabled = false;\n  });\n\n  function wait(ms) { return new Promise((r) => setTimeout(r, ms)); }\n\n  function logStep(item) {\n    const li = document.createElement(\"li\");\n    li.innerHTML = `${item.label} \u003Cspan class=\"tag\">— ${KIND_LABEL[item.kind]}\u003C\u002Fspan>`;\n    logList.appendChild(li);\n    logEmpty.style.display = \"none\";\n  }\n\n  async function run() {\n    if (!queued.length) return;\n    $(\"run\").disabled = true;\n    logList.innerHTML = \"\"; logEmpty.style.display = \"none\";\n\n    const micro = [];\n    const macro = [];\n\n    \u002F\u002F Phase 1: run the \"script\" top to bottom — this is the call stack.\n    for (const item of queued) {\n      render([item], stackEl, item.id);\n      $(\"stackTag\").textContent = \"running\";\n      await wait(500);\n      if (item.kind === \"sync\") {\n        logStep(item);\n      } else if (item.kind === \"micro\") {\n        micro.push(item);\n        render(micro, microEl);\n        $(\"microTag\").textContent = `+${micro.length}`;\n      } else {\n        macro.push(item);\n        render(macro, macroEl);\n        $(\"macroTag\").textContent = `+${macro.length}`;\n      }\n    }\n    render([], stackEl); $(\"stackTag\").textContent = \"empty\";\n    await wait(400);\n\n    \u002F\u002F Phase 2: drain the ENTIRE microtask queue before any macrotask.\n    while (micro.length) {\n      const item = micro.shift();\n      render(micro, microEl, item.id);\n      $(\"microTag\").textContent = \"draining\";\n      await wait(500);\n      logStep(item);\n    }\n    render([], microEl); $(\"microTag\").textContent = \"empty\";\n    await wait(400);\n\n    \u002F\u002F Phase 3: run macrotasks, one per turn (all queued ones here for clarity).\n    while (macro.length) {\n      const item = macro.shift();\n      render(macro, macroEl, item.id);\n      $(\"macroTag\").textContent = \"running\";\n      await wait(500);\n      logStep(item);\n    }\n    render([], macroEl); $(\"macroTag\").textContent = \"empty\";\n\n    $(\"run\").disabled = false;\n  }\n\n  $(\"run\").addEventListener(\"click\", run);\n\n  addWork(\"sync\"); addWork(\"macro\"); addWork(\"micro\"); addWork(\"sync\");",{"height":40,"autorun":17},520,{"slug":33,"title":42,"excerpt":43,"coverUrl":44},"JavaScript Event Loop Explained: The Complete Guide","Learn how the JavaScript event loop really works — call stack, microtasks, and macrotasks — with worked examples, edge cases, and a cheat sheet.","\u002Fmedia\u002Fcovers\u002Fweekly-javascript-event-loop.png"]