[{"data":1,"prerenderedAt":1032},["ShallowReactive",2],{"sidebar-course-\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop":3,"i-lucide:chevron-down":44,"i-lucide:search":48,"i-lucide:sun":50,"i-lucide:moon":52,"i-lucide:arrow-right":54,"i-lucide:menu":56,"i-lucide:panel-left":58,"i-lucide:mail":60,"i-simple-icons:x":62,"i-simple-icons:linkedin":64,"i-simple-icons:dribbble":66,"i-simple-icons:github":68,"lessons-\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop":70,"sidebar-quiz-\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop":901,"i-lucide:workflow":902,"i-lucide:circle-check-big":904,"i-lucide:printer":906,"i-lucide:graduation-cap":908,"i-lucide:book-marked":910,"i-lucide:notebook-pen":912,"quiz-\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop":914,"quiz-topic-\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop":1016,"i-lucide:chevron-right":1028,"i-lucide:percent":1030},{"id":4,"title":5,"access":6,"body":7,"description":14,"draft":15,"estimatedMinutes":16,"extension":17,"featured":18,"icon":19,"lang":20,"level":21,"meta":22,"navigation":18,"order":23,"path":24,"prerequisites":25,"resources":26,"seo":31,"sku":32,"stem":33,"subjects":34,"summary":36,"tags":37,"updated":42,"__hash__":43},"courses\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop\u002Findex.md","The event loop","free",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",3,[],"Call stack, task queues and microtasks — why your code ran in that order.",false,30,"md",true,"lucide:workflow","en","intermediate",{},1,"\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop",[],[27],{"label":28,"file":29,"access":6,"size":30},"Event loop reference card","js-event-loop-card.pdf","95 KB",{"title":5,"description":14},null,"learn\u002Fen\u002Fcourses\u002Fevent-loop\u002Findex",[35],"javascript","JavaScript runs on one thread with one call stack. Anything asynchronous is\nhanded to the host environment, which puts a callback in a queue when it is\nready. The event loop moves work from those queues onto the stack, but only\nwhen the stack is empty. Microtasks — promise continuations — drain completely\nbetween each task, which is why an await resolves before a setTimeout of zero.\nAlmost every ordering surprise in JavaScript follows from those rules.\n",[38,39,40,41],"async","promises","runtime","concurrency","2026-08-05","BOC7v_GWQoKJp-mEK6X_H0pY-0KcxkhIWnXKWsm8c9k",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":47},0,24,"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m6 9l6 6l6-6\"\u002F>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":49},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"m21 21l-4.34-4.34\"\u002F>\u003Ccircle cx=\"11\" cy=\"11\" r=\"8\"\u002F>\u003C\u002Fg>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":51},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"4\"\u002F>\u003Cpath d=\"M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32l1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41\"\u002F>\u003C\u002Fg>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":53},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\u002F>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":55},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 12h14m-7-7l7 7l-7 7\"\u002F>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":57},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5h16M4 12h16M4 19h16\"\u002F>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":59},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Crect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\"\u002F>\u003Cpath d=\"M9 3v18\"\u002F>\u003C\u002Fg>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":61},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"m22 7l-8.991 5.727a2 2 0 0 1-2.009 0L2 7\"\u002F>\u003Crect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\"\u002F>\u003C\u002Fg>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":63},"\u003Cpath fill=\"currentColor\" d=\"M14.234 10.162L22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299l-.929-1.329L3.076 1.56h3.182l5.965 8.532l.929 1.329l7.754 11.09h-3.182z\"\u002F>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":65,"hidden":18},"\u003Cpath fill=\"currentColor\" d=\"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037c-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85c3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.06 2.06 0 0 1-2.063-2.065a2.064 2.064 0 1 1 2.063 2.065m1.782 13.019H3.555V9h3.564zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0z\"\u002F>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":67},"\u003Cpath fill=\"currentColor\" d=\"M12 24C5.385 24 0 18.615 0 12S5.385 0 12 0s12 5.385 12 12s-5.385 12-12 12m10.12-10.358c-.35-.11-3.17-.953-6.384-.438c1.34 3.684 1.887 6.684 1.992 7.308a10.28 10.28 0 0 0 4.395-6.87zm-6.115 7.808c-.153-.9-.75-4.032-2.19-7.77l-.066.02c-5.79 2.015-7.86 6.025-8.04 6.4a10.16 10.16 0 0 0 6.29 2.166c1.42 0 2.77-.29 4-.814zm-11.62-2.58c.232-.4 3.045-5.055 8.332-6.765q.202-.067.405-.12q-.392-.879-.832-1.74C7.17 11.775 2.206 11.71 1.756 11.7l-.004.312c0 2.633.998 5.037 2.634 6.855zm-2.42-8.955c.46.008 4.683.026 9.477-1.248a66 66 0 0 0-3.8-5.928a10.28 10.28 0 0 0-5.676 7.17zM9.6 2.052c.282.38 2.145 2.914 3.822 6c3.645-1.365 5.19-3.44 5.373-3.702A10.2 10.2 0 0 0 12 1.764c-.825 0-1.63.1-2.4.285zm10.335 3.483c-.218.29-1.935 2.493-5.724 4.04c.24.49.47.985.68 1.486c.08.18.15.36.22.53c3.41-.43 6.8.26 7.14.33c-.02-2.42-.88-4.64-2.31-6.38z\"\u002F>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":69},"\u003Cpath fill=\"currentColor\" d=\"M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\"\u002F>",[71,470],{"id":72,"title":73,"access":6,"body":74,"description":464,"extension":17,"lang":20,"meta":465,"navigation":18,"order":23,"partial":15,"path":466,"seo":467,"stem":468,"__hash__":469},"lessons\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop\u002F01.call-stack.md","The call stack",{"type":8,"value":75,"toc":459},[76,80,84,187,194,199,202,205,264,270,274,282,293,361,366,370,373,442,455],[77,78,73],"h1",{"id":79},"the-call-stack",[81,82,83],"p",{},"JavaScript has a single call stack. One thing executes at a time, and a function\nruns to completion before anything else gets a turn.",[85,86,90],"pre",{"className":87,"code":88,"language":89,"meta":11,"style":11},"language-js shiki shiki-themes github-dark-dimmed github-dark-dimmed","function third() {\n  return 'done'\n}\nfunction second() {\n  return third()\n}\nfunction first() {\n  return second()\n}\n\nfirst()\n","js",[91,92,93,109,119,124,134,144,149,159,168,173,179],"code",{"__ignoreMap":11},[94,95,97,101,105],"span",{"class":96,"line":23},"line",[94,98,100],{"class":99},"sEYkB","function",[94,102,104],{"class":103},"s-wk_"," third",[94,106,108],{"class":107},"sM9_K","() {\n",[94,110,112,115],{"class":96,"line":111},2,[94,113,114],{"class":99},"  return",[94,116,118],{"class":117},"szYpP"," 'done'\n",[94,120,121],{"class":96,"line":12},[94,122,123],{"class":107},"}\n",[94,125,127,129,132],{"class":96,"line":126},4,[94,128,100],{"class":99},[94,130,131],{"class":103}," second",[94,133,108],{"class":107},[94,135,137,139,141],{"class":96,"line":136},5,[94,138,114],{"class":99},[94,140,104],{"class":103},[94,142,143],{"class":107},"()\n",[94,145,147],{"class":96,"line":146},6,[94,148,123],{"class":107},[94,150,152,154,157],{"class":96,"line":151},7,[94,153,100],{"class":99},[94,155,156],{"class":103}," first",[94,158,108],{"class":107},[94,160,162,164,166],{"class":96,"line":161},8,[94,163,114],{"class":99},[94,165,131],{"class":103},[94,167,143],{"class":107},[94,169,171],{"class":96,"line":170},9,[94,172,123],{"class":107},[94,174,176],{"class":96,"line":175},10,[94,177,178],{"emptyLinePlaceholder":18},"\n",[94,180,182,185],{"class":96,"line":181},11,[94,183,184],{"class":103},"first",[94,186,143],{"class":107},[81,188,189,190,193],{},"The stack grows to ",[91,191,192],{},"first → second → third",", then unwinds. Nothing interleaves.",[195,196,198],"h2",{"id":197},"run-to-completion-is-a-guarantee","Run-to-completion is a guarantee",[81,200,201],{},"Once a function starts, no other JavaScript can run until it returns. This is why\nyou never need locks around a shared variable: no other code can observe an\nintermediate state.",[81,203,204],{},"It is also why one slow function freezes everything:",[85,206,208],{"className":87,"code":207,"language":89,"meta":11,"style":11},"const start = Date.now()\nwhile (Date.now() - start \u003C 5000) {}\n\u002F\u002F Nothing else runs for five seconds — no clicks, no timers, no rendering.\n",[91,209,210,230,258],{"__ignoreMap":11},[94,211,212,215,219,222,225,228],{"class":96,"line":23},[94,213,214],{"class":99},"const",[94,216,218],{"class":217},"sQdni"," start",[94,220,221],{"class":99}," =",[94,223,224],{"class":107}," Date.",[94,226,227],{"class":103},"now",[94,229,143],{"class":107},[94,231,232,235,238,240,243,246,249,252,255],{"class":96,"line":111},[94,233,234],{"class":99},"while",[94,236,237],{"class":107}," (Date.",[94,239,227],{"class":103},[94,241,242],{"class":107},"() ",[94,244,245],{"class":99},"-",[94,247,248],{"class":107}," start ",[94,250,251],{"class":99},"\u003C",[94,253,254],{"class":217}," 5000",[94,256,257],{"class":107},") {}\n",[94,259,260],{"class":96,"line":12},[94,261,263],{"class":262},"s0RzX","\u002F\u002F Nothing else runs for five seconds — no clicks, no timers, no rendering.\n",[265,266,267],"warning",{},[81,268,269],{},"\"Blocking the event loop\" is not a metaphor. On the main thread of a browser, a\nlong synchronous loop blocks rendering, input handling and every pending callback.\nThe tab is frozen for the duration, and the browser may offer to kill it.",[195,271,273],{"id":272},"where-async-work-actually-happens","Where async work actually happens",[81,275,276,277,281],{},"The runtime is single-threaded. The ",[278,279,280],"em",{},"environment"," around it is not.",[81,283,284,285,288,289,292],{},"When you call ",[91,286,287],{},"setTimeout",", the timer is not JavaScript — it is the host. When you\ncall ",[91,290,291],{},"fetch",", the network request is handled by the browser's networking stack on\nanother thread. Your callback is simply registered.",[85,294,296],{"className":87,"code":295,"language":89,"meta":11,"style":11},"console.log('1')\nsetTimeout(() => console.log('3'), 0)\nconsole.log('2')\n\u002F\u002F 1, 2, 3\n",[91,297,298,315,343,356],{"__ignoreMap":11},[94,299,300,303,306,309,312],{"class":96,"line":23},[94,301,302],{"class":107},"console.",[94,304,305],{"class":103},"log",[94,307,308],{"class":107},"(",[94,310,311],{"class":117},"'1'",[94,313,314],{"class":107},")\n",[94,316,317,319,322,325,328,330,332,335,338,341],{"class":96,"line":111},[94,318,287],{"class":103},[94,320,321],{"class":107},"(() ",[94,323,324],{"class":99},"=>",[94,326,327],{"class":107}," console.",[94,329,305],{"class":103},[94,331,308],{"class":107},[94,333,334],{"class":117},"'3'",[94,336,337],{"class":107},"), ",[94,339,340],{"class":217},"0",[94,342,314],{"class":107},[94,344,345,347,349,351,354],{"class":96,"line":12},[94,346,302],{"class":107},[94,348,305],{"class":103},[94,350,308],{"class":107},[94,352,353],{"class":117},"'2'",[94,355,314],{"class":107},[94,357,358],{"class":96,"line":126},[94,359,360],{"class":262},"\u002F\u002F 1, 2, 3\n",[81,362,363,365],{},[91,364,287],{}," returns immediately. The callback is queued for later even with a zero\ndelay, because \"later\" means \"once the stack is empty\" — not \"in zero milliseconds\".",[195,367,369],{"id":368},"the-stack-in-a-stack-trace","The stack in a stack trace",[81,371,372],{},"An error captures the stack at the moment it is thrown. In async code, the stack\nyou get is the one at callback time, not at scheduling time:",[85,374,376],{"className":87,"code":375,"language":89,"meta":11,"style":11},"function schedule() {\n  setTimeout(() => {\n    throw new Error('boom')\n  }, 0)\n}\nschedule()\n\u002F\u002F The trace shows the timer callback. `schedule` is long gone.\n",[91,377,378,387,399,417,426,430,437],{"__ignoreMap":11},[94,379,380,382,385],{"class":96,"line":23},[94,381,100],{"class":99},[94,383,384],{"class":103}," schedule",[94,386,108],{"class":107},[94,388,389,392,394,396],{"class":96,"line":111},[94,390,391],{"class":103},"  setTimeout",[94,393,321],{"class":107},[94,395,324],{"class":99},[94,397,398],{"class":107}," {\n",[94,400,401,404,407,410,412,415],{"class":96,"line":12},[94,402,403],{"class":99},"    throw",[94,405,406],{"class":99}," new",[94,408,409],{"class":103}," Error",[94,411,308],{"class":107},[94,413,414],{"class":117},"'boom'",[94,416,314],{"class":107},[94,418,419,422,424],{"class":96,"line":126},[94,420,421],{"class":107},"  }, ",[94,423,340],{"class":217},[94,425,314],{"class":107},[94,427,428],{"class":96,"line":136},[94,429,123],{"class":107},[94,431,432,435],{"class":96,"line":146},[94,433,434],{"class":103},"schedule",[94,436,143],{"class":107},[94,438,439],{"class":96,"line":151},[94,440,441],{"class":262},"\u002F\u002F The trace shows the timer callback. `schedule` is long gone.\n",[81,443,444,445,448,449,451,452,454],{},"Modern engines reconstruct async stack traces across ",[91,446,447],{},"await"," boundaries, which is\none practical reason to prefer ",[91,450,38],{},"\u002F",[91,453,447],{}," over raw callbacks.",[456,457,458],"style",{},"html pre.shiki code .sEYkB, html code.shiki .sEYkB{--shiki-default:#F47067;--shiki-dark:#F47067}html pre.shiki code .s-wk_, html code.shiki .s-wk_{--shiki-default:#DCBDFB;--shiki-dark:#DCBDFB}html pre.shiki code .sM9_K, html code.shiki .sM9_K{--shiki-default:#ADBAC7;--shiki-dark:#ADBAC7}html pre.shiki code .szYpP, html code.shiki .szYpP{--shiki-default:#96D0FF;--shiki-dark:#96D0FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQdni, html code.shiki .sQdni{--shiki-default:#6CB6FF;--shiki-dark:#6CB6FF}html pre.shiki code .s0RzX, html code.shiki .s0RzX{--shiki-default:#768390;--shiki-dark:#768390}",{"title":11,"searchDepth":12,"depth":12,"links":460},[461,462,463],{"id":197,"depth":111,"text":198},{"id":272,"depth":111,"text":273},{"id":368,"depth":111,"text":369},"One thread, one stack, and what \"blocking\" actually blocks.",{},"\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop\u002Fcall-stack",{"title":73,"description":464},"learn\u002Fen\u002Fcourses\u002Fevent-loop\u002F01.call-stack","BiJN8dMZjgvIkocYL4WlAg539TRcbZZHnuwy9Hi7GFg",{"id":471,"title":472,"access":6,"body":473,"description":895,"extension":17,"lang":20,"meta":896,"navigation":18,"order":111,"partial":15,"path":897,"seo":898,"stem":899,"__hash__":900},"lessons\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop\u002F02.task-queues.md","Tasks and microtasks",{"type":8,"value":474,"toc":889},[475,478,481,538,542,550,674,677,685,688,692,697,785,798,802,805,857,870,874,877,886],[77,476,472],{"id":477},"tasks-and-microtasks",[81,479,480],{},"There is not one queue. There are two, and they are drained differently.",[482,483,484,500],"table",{},[485,486,487],"thead",{},[488,489,490,494,497],"tr",{},[491,492,493],"th",{},"Queue",[491,495,496],{},"Sources",[491,498,499],{},"Drained",[501,502,503,521],"tbody",{},[488,504,505,509,518],{},[506,507,508],"td",{},"Task (macrotask)",[506,510,511,513,514,517],{},[91,512,287],{},", ",[91,515,516],{},"setInterval",", I\u002FO, events",[506,519,520],{},"One per loop iteration",[488,522,523,526,535],{},[506,524,525],{},"Microtask",[506,527,528,529,513,532],{},"Promise callbacks, ",[91,530,531],{},"queueMicrotask",[91,533,534],{},"MutationObserver",[506,536,537],{},"Completely, after every task",[195,539,541],{"id":540},"the-rule","The rule",[81,543,544,545,549],{},"After the stack empties, the event loop drains ",[546,547,548],"strong",{},"the entire microtask queue"," before\ntaking the next task. Microtasks added while draining are also processed in the same\npass.",[85,551,553],{"className":87,"code":552,"language":89,"meta":11,"style":11},"console.log('script start')\n\nsetTimeout(() => console.log('timeout'), 0)\n\nPromise.resolve()\n  .then(() => console.log('promise 1'))\n  .then(() => console.log('promise 2'))\n\nconsole.log('script end')\n",[91,554,555,568,572,595,599,612,636,657,661],{"__ignoreMap":11},[94,556,557,559,561,563,566],{"class":96,"line":23},[94,558,302],{"class":107},[94,560,305],{"class":103},[94,562,308],{"class":107},[94,564,565],{"class":117},"'script start'",[94,567,314],{"class":107},[94,569,570],{"class":96,"line":111},[94,571,178],{"emptyLinePlaceholder":18},[94,573,574,576,578,580,582,584,586,589,591,593],{"class":96,"line":12},[94,575,287],{"class":103},[94,577,321],{"class":107},[94,579,324],{"class":99},[94,581,327],{"class":107},[94,583,305],{"class":103},[94,585,308],{"class":107},[94,587,588],{"class":117},"'timeout'",[94,590,337],{"class":107},[94,592,340],{"class":217},[94,594,314],{"class":107},[94,596,597],{"class":96,"line":126},[94,598,178],{"emptyLinePlaceholder":18},[94,600,601,604,607,610],{"class":96,"line":136},[94,602,603],{"class":217},"Promise",[94,605,606],{"class":107},".",[94,608,609],{"class":103},"resolve",[94,611,143],{"class":107},[94,613,614,617,620,622,624,626,628,630,633],{"class":96,"line":146},[94,615,616],{"class":107},"  .",[94,618,619],{"class":103},"then",[94,621,321],{"class":107},[94,623,324],{"class":99},[94,625,327],{"class":107},[94,627,305],{"class":103},[94,629,308],{"class":107},[94,631,632],{"class":117},"'promise 1'",[94,634,635],{"class":107},"))\n",[94,637,638,640,642,644,646,648,650,652,655],{"class":96,"line":151},[94,639,616],{"class":107},[94,641,619],{"class":103},[94,643,321],{"class":107},[94,645,324],{"class":99},[94,647,327],{"class":107},[94,649,305],{"class":103},[94,651,308],{"class":107},[94,653,654],{"class":117},"'promise 2'",[94,656,635],{"class":107},[94,658,659],{"class":96,"line":161},[94,660,178],{"emptyLinePlaceholder":18},[94,662,663,665,667,669,672],{"class":96,"line":170},[94,664,302],{"class":107},[94,666,305],{"class":103},[94,668,308],{"class":107},[94,670,671],{"class":117},"'script end'",[94,673,314],{"class":107},[81,675,676],{},"Output:",[85,678,683],{"className":679,"code":681,"language":682,"meta":11},[680],"language-text","script start\nscript end\npromise 1\npromise 2\ntimeout\n","text",[91,684,681],{"__ignoreMap":11},[81,686,687],{},"Both promise callbacks run before the timeout, even though the timeout was scheduled\nfirst. They are microtasks; the timeout is a task.",[195,689,691],{"id":690},"await-is-a-microtask-boundary","await is a microtask boundary",[81,693,694,696],{},[91,695,447],{}," suspends the function and schedules the remainder as a promise continuation:",[85,698,700],{"className":87,"code":699,"language":89,"meta":11,"style":11},"async function run() {\n  console.log('a')\n  await null \u002F\u002F still a microtask, even awaiting a non-promise\n  console.log('c')\n}\n\nrun()\nconsole.log('b')\n\u002F\u002F a, b, c\n",[91,701,702,714,728,739,752,756,760,767,780],{"__ignoreMap":11},[94,703,704,706,709,712],{"class":96,"line":23},[94,705,38],{"class":99},[94,707,708],{"class":99}," function",[94,710,711],{"class":103}," run",[94,713,108],{"class":107},[94,715,716,719,721,723,726],{"class":96,"line":111},[94,717,718],{"class":107},"  console.",[94,720,305],{"class":103},[94,722,308],{"class":107},[94,724,725],{"class":117},"'a'",[94,727,314],{"class":107},[94,729,730,733,736],{"class":96,"line":12},[94,731,732],{"class":99},"  await",[94,734,735],{"class":217}," null",[94,737,738],{"class":262}," \u002F\u002F still a microtask, even awaiting a non-promise\n",[94,740,741,743,745,747,750],{"class":96,"line":126},[94,742,718],{"class":107},[94,744,305],{"class":103},[94,746,308],{"class":107},[94,748,749],{"class":117},"'c'",[94,751,314],{"class":107},[94,753,754],{"class":96,"line":136},[94,755,123],{"class":107},[94,757,758],{"class":96,"line":146},[94,759,178],{"emptyLinePlaceholder":18},[94,761,762,765],{"class":96,"line":151},[94,763,764],{"class":103},"run",[94,766,143],{"class":107},[94,768,769,771,773,775,778],{"class":96,"line":161},[94,770,302],{"class":107},[94,772,305],{"class":103},[94,774,308],{"class":107},[94,776,777],{"class":117},"'b'",[94,779,314],{"class":107},[94,781,782],{"class":96,"line":170},[94,783,784],{"class":262},"\u002F\u002F a, b, c\n",[81,786,787,790,791,793,794,797],{},[91,788,789],{},"await null"," does not skip the queue. Everything after the ",[91,792,447],{}," becomes a\nmicrotask, so the synchronous ",[91,795,796],{},"console.log('b')"," runs first.",[195,799,801],{"id":800},"starving-the-loop","Starving the loop",[81,803,804],{},"Because microtasks drain completely, a microtask that schedules another microtask\nforever prevents any task from ever running:",[85,806,808],{"className":87,"code":807,"language":89,"meta":11,"style":11},"function spin() {\n  Promise.resolve().then(spin)\n}\nspin()\n\u002F\u002F Timers never fire. Rendering never happens. The page is frozen —\n\u002F\u002F but the CPU profile looks like idle promise work, not a busy loop.\n",[91,809,810,819,836,840,847,852],{"__ignoreMap":11},[94,811,812,814,817],{"class":96,"line":23},[94,813,100],{"class":99},[94,815,816],{"class":103}," spin",[94,818,108],{"class":107},[94,820,821,824,826,828,831,833],{"class":96,"line":111},[94,822,823],{"class":217},"  Promise",[94,825,606],{"class":107},[94,827,609],{"class":103},[94,829,830],{"class":107},"().",[94,832,619],{"class":103},[94,834,835],{"class":107},"(spin)\n",[94,837,838],{"class":96,"line":12},[94,839,123],{"class":107},[94,841,842,845],{"class":96,"line":126},[94,843,844],{"class":103},"spin",[94,846,143],{"class":107},[94,848,849],{"class":96,"line":136},[94,850,851],{"class":262},"\u002F\u002F Timers never fire. Rendering never happens. The page is frozen —\n",[94,853,854],{"class":96,"line":146},[94,855,856],{"class":262},"\u002F\u002F but the CPU profile looks like idle promise work, not a busy loop.\n",[858,859,860],"danger",{},[81,861,862,863,866,867,869],{},"This is worse than a ",[91,864,865],{},"while (true)"," loop, because it is harder to spot. The stack is\nshallow, each individual microtask is fast, and nothing looks obviously wrong. Use\n",[91,868,287],{}," rather than promise recursion for anything that repeats indefinitely.",[195,871,873],{"id":872},"rendering","Rendering",[81,875,876],{},"In a browser, rendering is neither a task nor a microtask — it happens between\ntasks, at most once per frame. Since microtasks drain before rendering, a long\nmicrotask chain delays paint just as effectively as blocking code.",[878,879,880],"tip",{},[81,881,882,885],{},[91,883,884],{},"requestAnimationFrame"," callbacks run just before paint, after microtasks. That is\nthe correct place for visual updates, and the wrong place for anything expensive.",[456,887,888],{},"html pre.shiki code .sM9_K, html code.shiki .sM9_K{--shiki-default:#ADBAC7;--shiki-dark:#ADBAC7}html pre.shiki code .s-wk_, html code.shiki .s-wk_{--shiki-default:#DCBDFB;--shiki-dark:#DCBDFB}html pre.shiki code .szYpP, html code.shiki .szYpP{--shiki-default:#96D0FF;--shiki-dark:#96D0FF}html pre.shiki code .sEYkB, html code.shiki .sEYkB{--shiki-default:#F47067;--shiki-dark:#F47067}html pre.shiki code .sQdni, html code.shiki .sQdni{--shiki-default:#6CB6FF;--shiki-dark:#6CB6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s0RzX, html code.shiki .s0RzX{--shiki-default:#768390;--shiki-dark:#768390}",{"title":11,"searchDepth":12,"depth":12,"links":890},[891,892,893,894],{"id":540,"depth":111,"text":541},{"id":690,"depth":111,"text":691},{"id":800,"depth":111,"text":801},{"id":872,"depth":111,"text":873},"Two queues, different draining rules, and the ordering that follows.",{},"\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop\u002Ftask-queues",{"title":472,"description":895},"learn\u002Fen\u002Fcourses\u002Fevent-loop\u002F02.task-queues","Jzwld-KwT30H_KYGrTndaDQB3plJFyiXJ-0rWZCopTQ",{"course":24},{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":903},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Crect width=\"8\" height=\"8\" x=\"3\" y=\"3\" rx=\"2\"\u002F>\u003Cpath d=\"M7 11v4a2 2 0 0 0 2 2h4\"\u002F>\u003Crect width=\"8\" height=\"8\" x=\"13\" y=\"13\" rx=\"2\"\u002F>\u003C\u002Fg>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":905},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M21.801 10A10 10 0 1 1 17 3.335\"\u002F>\u003Cpath d=\"m9 11l3 3L22 4\"\u002F>\u003C\u002Fg>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":907},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2M6 9V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v6\"\u002F>\u003Crect width=\"12\" height=\"8\" x=\"6\" y=\"14\" rx=\"1\"\u002F>\u003C\u002Fg>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":909},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0zM22 10v6\"\u002F>\u003Cpath d=\"M6 12.5V16a6 3 0 0 0 12 0v-3.5\"\u002F>\u003C\u002Fg>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":911},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M10 2v8l3-3l3 3V2\"\u002F>\u003Cpath d=\"M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20\"\u002F>\u003C\u002Fg>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":913},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M13.4 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7.4M2 6h4m-4 4h4m-4 4h4m-4 4h4\"\u002F>\u003Cpath d=\"M21.378 5.626a1 1 0 1 0-3.004-3.004l-5.01 5.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z\"\u002F>\u003C\u002Fg>",{"id":915,"title":5,"course":24,"description":916,"extension":917,"lang":20,"meta":918,"passingScore":919,"questions":920,"shuffle":18,"stem":1014,"__hash__":1015},"quizzes\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop\u002Fquiz.yml","Six questions on ordering, queues and blocking.","yml",{},70,[921,941,957,972,986,1000],{"id":922,"question":923,"type":924,"difficulty":925,"options":926,"correct":939,"explanation":940},"order-basic","What does this print? console.log('1'); setTimeout(() => console.log('3'), 0); console.log('2')","single","easy",[927,930,933,936],{"id":928,"text":929},"a","1, 2, 3",{"id":931,"text":932},"b","1, 3, 2",{"id":934,"text":935},"c","3, 1, 2",{"id":937,"text":938},"d","The order is not deterministic",[928],"setTimeout queues a task regardless of the delay. Tasks only run once the stack is empty, so both synchronous logs happen first.\n",{"id":942,"question":943,"type":944,"difficulty":945,"options":946,"correct":955,"explanation":956},"micro-vs-macro","Which of these schedule microtasks rather than tasks?","multiple","medium",[947,949,951,953],{"id":928,"text":948},"Promise.resolve().then(fn)",{"id":931,"text":950},"queueMicrotask(fn)",{"id":934,"text":952},"setTimeout(fn, 0)",{"id":937,"text":954},"The continuation after an await",[928,931,937],"Promise continuations, queueMicrotask and everything after an await are microtasks. setTimeout always queues a task, even with a zero delay.\n",{"id":958,"question":959,"type":924,"difficulty":960,"options":961,"correct":970,"explanation":971},"await-null","Does `await null` yield to the microtask queue?","hard",[962,964,966,968],{"id":928,"text":963},"No — awaiting a non-promise resolves synchronously",{"id":931,"text":965},"Yes — the rest of the function becomes a microtask either way",{"id":934,"text":967},"Only in strict mode",{"id":937,"text":969},"Only if the function was called from another async function",[931],"await always suspends. The value is wrapped and the remainder of the function is scheduled as a promise continuation, non-promise operand or not.\n",{"id":973,"question":974,"type":924,"difficulty":945,"options":975,"correct":984,"explanation":985},"drain-rule","How much of the microtask queue is drained between two tasks?",[976,978,980,982],{"id":928,"text":977},"One microtask",{"id":931,"text":979},"All of it, including microtasks added during the drain",{"id":934,"text":981},"All of it, but newly added ones wait for the next pass",{"id":937,"text":983},"As many as fit in the current frame budget",[931],"The queue is drained to empty. Microtasks enqueued while draining join the same pass, which is what makes infinite microtask recursion able to starve the loop entirely.\n",{"id":987,"question":988,"type":924,"difficulty":960,"options":989,"correct":998,"explanation":999},"starvation","Why is infinite promise recursion harder to diagnose than a while(true) loop?",[990,992,994,996],{"id":928,"text":991},"It only reproduces under load",{"id":931,"text":993},"The stack stays shallow and each microtask completes quickly",{"id":934,"text":995},"Browsers suppress errors inside promises",{"id":937,"text":997},"It does not actually block rendering",[931],"Each individual microtask returns immediately and the stack never grows, so nothing looks stuck — but the queue never empties, so no task or paint ever runs.\n",{"id":1001,"question":1002,"type":924,"difficulty":945,"options":1003,"correct":1012,"explanation":1013},"raf","When do requestAnimationFrame callbacks run?",[1004,1006,1008,1010],{"id":928,"text":1005},"Before microtasks are drained",{"id":931,"text":1007},"After microtasks, just before paint",{"id":934,"text":1009},"At the same priority as setTimeout(fn, 16)",{"id":937,"text":1011},"On a separate thread from the main loop",[931],"rAF callbacks run in the rendering step, after the microtask queue has drained, immediately before the browser paints the frame.\n","learn\u002Fen\u002Fcourses\u002Fevent-loop\u002Fquiz","5l1vwZesuivBxzEwvXYasWr9Nz10Iq2OmAFu7gZH1E4",{"id":4,"title":5,"access":6,"body":1017,"description":14,"draft":15,"estimatedMinutes":16,"extension":17,"featured":18,"icon":19,"lang":20,"level":21,"meta":1021,"navigation":18,"order":23,"path":24,"prerequisites":1022,"resources":1023,"seo":1025,"sku":32,"stem":33,"subjects":1026,"summary":36,"tags":1027,"updated":42,"__hash__":43},{"type":8,"value":1018,"toc":1019},[],{"title":11,"searchDepth":12,"depth":12,"links":1020},[],{},[],[1024],{"label":28,"file":29,"access":6,"size":30},{"title":5,"description":14},[35],[38,39,40,41],{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":1029},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m9 18l6-6l-6-6\"\u002F>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":1031},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M19 5L5 19\"\u002F>\u003Ccircle cx=\"6.5\" cy=\"6.5\" r=\"2.5\"\u002F>\u003Ccircle cx=\"17.5\" cy=\"17.5\" r=\"2.5\"\u002F>\u003C\u002Fg>",1787597904757]