[{"data":1,"prerenderedAt":1034},["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,"i-lucide:arrow-up-right":70,"lessons-\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop":72,"sidebar-quiz-\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop":903,"i-lucide:workflow":904,"i-lucide:circle-check-big":906,"i-lucide:printer":908,"i-lucide:graduation-cap":910,"i-lucide:book-marked":912,"i-lucide:notebook-pen":914,"quiz-\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop":916,"quiz-topic-\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop":1018,"i-lucide:chevron-right":1030,"i-lucide:percent":1032},{"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>",{"left":45,"top":45,"width":46,"height":46,"rotate":45,"vFlip":15,"hFlip":15,"body":71},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M7 7h10v10M7 17L17 7\"\u002F>",[73,472],{"id":74,"title":75,"access":6,"body":76,"description":466,"extension":17,"lang":20,"meta":467,"navigation":18,"order":23,"partial":15,"path":468,"seo":469,"stem":470,"__hash__":471},"lessons\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop\u002F01.call-stack.md","The call stack",{"type":8,"value":77,"toc":461},[78,82,86,189,196,201,204,207,266,272,276,284,295,363,368,372,375,444,457],[79,80,75],"h1",{"id":81},"the-call-stack",[83,84,85],"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.",[87,88,92],"pre",{"className":89,"code":90,"language":91,"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",[93,94,95,111,121,126,136,146,151,161,170,175,181],"code",{"__ignoreMap":11},[96,97,99,103,107],"span",{"class":98,"line":23},"line",[96,100,102],{"class":101},"sEYkB","function",[96,104,106],{"class":105},"s-wk_"," third",[96,108,110],{"class":109},"sM9_K","() {\n",[96,112,114,117],{"class":98,"line":113},2,[96,115,116],{"class":101},"  return",[96,118,120],{"class":119},"szYpP"," 'done'\n",[96,122,123],{"class":98,"line":12},[96,124,125],{"class":109},"}\n",[96,127,129,131,134],{"class":98,"line":128},4,[96,130,102],{"class":101},[96,132,133],{"class":105}," second",[96,135,110],{"class":109},[96,137,139,141,143],{"class":98,"line":138},5,[96,140,116],{"class":101},[96,142,106],{"class":105},[96,144,145],{"class":109},"()\n",[96,147,149],{"class":98,"line":148},6,[96,150,125],{"class":109},[96,152,154,156,159],{"class":98,"line":153},7,[96,155,102],{"class":101},[96,157,158],{"class":105}," first",[96,160,110],{"class":109},[96,162,164,166,168],{"class":98,"line":163},8,[96,165,116],{"class":101},[96,167,133],{"class":105},[96,169,145],{"class":109},[96,171,173],{"class":98,"line":172},9,[96,174,125],{"class":109},[96,176,178],{"class":98,"line":177},10,[96,179,180],{"emptyLinePlaceholder":18},"\n",[96,182,184,187],{"class":98,"line":183},11,[96,185,186],{"class":105},"first",[96,188,145],{"class":109},[83,190,191,192,195],{},"The stack grows to ",[93,193,194],{},"first → second → third",", then unwinds. Nothing interleaves.",[197,198,200],"h2",{"id":199},"run-to-completion-is-a-guarantee","Run-to-completion is a guarantee",[83,202,203],{},"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.",[83,205,206],{},"It is also why one slow function freezes everything:",[87,208,210],{"className":89,"code":209,"language":91,"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",[93,211,212,232,260],{"__ignoreMap":11},[96,213,214,217,221,224,227,230],{"class":98,"line":23},[96,215,216],{"class":101},"const",[96,218,220],{"class":219},"sQdni"," start",[96,222,223],{"class":101}," =",[96,225,226],{"class":109}," Date.",[96,228,229],{"class":105},"now",[96,231,145],{"class":109},[96,233,234,237,240,242,245,248,251,254,257],{"class":98,"line":113},[96,235,236],{"class":101},"while",[96,238,239],{"class":109}," (Date.",[96,241,229],{"class":105},[96,243,244],{"class":109},"() ",[96,246,247],{"class":101},"-",[96,249,250],{"class":109}," start ",[96,252,253],{"class":101},"\u003C",[96,255,256],{"class":219}," 5000",[96,258,259],{"class":109},") {}\n",[96,261,262],{"class":98,"line":12},[96,263,265],{"class":264},"s0RzX","\u002F\u002F Nothing else runs for five seconds — no clicks, no timers, no rendering.\n",[267,268,269],"warning",{},[83,270,271],{},"\"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.",[197,273,275],{"id":274},"where-async-work-actually-happens","Where async work actually happens",[83,277,278,279,283],{},"The runtime is single-threaded. The ",[280,281,282],"em",{},"environment"," around it is not.",[83,285,286,287,290,291,294],{},"When you call ",[93,288,289],{},"setTimeout",", the timer is not JavaScript — it is the host. When you\ncall ",[93,292,293],{},"fetch",", the network request is handled by the browser's networking stack on\nanother thread. Your callback is simply registered.",[87,296,298],{"className":89,"code":297,"language":91,"meta":11,"style":11},"console.log('1')\nsetTimeout(() => console.log('3'), 0)\nconsole.log('2')\n\u002F\u002F 1, 2, 3\n",[93,299,300,317,345,358],{"__ignoreMap":11},[96,301,302,305,308,311,314],{"class":98,"line":23},[96,303,304],{"class":109},"console.",[96,306,307],{"class":105},"log",[96,309,310],{"class":109},"(",[96,312,313],{"class":119},"'1'",[96,315,316],{"class":109},")\n",[96,318,319,321,324,327,330,332,334,337,340,343],{"class":98,"line":113},[96,320,289],{"class":105},[96,322,323],{"class":109},"(() ",[96,325,326],{"class":101},"=>",[96,328,329],{"class":109}," console.",[96,331,307],{"class":105},[96,333,310],{"class":109},[96,335,336],{"class":119},"'3'",[96,338,339],{"class":109},"), ",[96,341,342],{"class":219},"0",[96,344,316],{"class":109},[96,346,347,349,351,353,356],{"class":98,"line":12},[96,348,304],{"class":109},[96,350,307],{"class":105},[96,352,310],{"class":109},[96,354,355],{"class":119},"'2'",[96,357,316],{"class":109},[96,359,360],{"class":98,"line":128},[96,361,362],{"class":264},"\u002F\u002F 1, 2, 3\n",[83,364,365,367],{},[93,366,289],{}," 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\".",[197,369,371],{"id":370},"the-stack-in-a-stack-trace","The stack in a stack trace",[83,373,374],{},"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:",[87,376,378],{"className":89,"code":377,"language":91,"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",[93,379,380,389,401,419,428,432,439],{"__ignoreMap":11},[96,381,382,384,387],{"class":98,"line":23},[96,383,102],{"class":101},[96,385,386],{"class":105}," schedule",[96,388,110],{"class":109},[96,390,391,394,396,398],{"class":98,"line":113},[96,392,393],{"class":105},"  setTimeout",[96,395,323],{"class":109},[96,397,326],{"class":101},[96,399,400],{"class":109}," {\n",[96,402,403,406,409,412,414,417],{"class":98,"line":12},[96,404,405],{"class":101},"    throw",[96,407,408],{"class":101}," new",[96,410,411],{"class":105}," Error",[96,413,310],{"class":109},[96,415,416],{"class":119},"'boom'",[96,418,316],{"class":109},[96,420,421,424,426],{"class":98,"line":128},[96,422,423],{"class":109},"  }, ",[96,425,342],{"class":219},[96,427,316],{"class":109},[96,429,430],{"class":98,"line":138},[96,431,125],{"class":109},[96,433,434,437],{"class":98,"line":148},[96,435,436],{"class":105},"schedule",[96,438,145],{"class":109},[96,440,441],{"class":98,"line":153},[96,442,443],{"class":264},"\u002F\u002F The trace shows the timer callback. `schedule` is long gone.\n",[83,445,446,447,450,451,453,454,456],{},"Modern engines reconstruct async stack traces across ",[93,448,449],{},"await"," boundaries, which is\none practical reason to prefer ",[93,452,38],{},"\u002F",[93,455,449],{}," over raw callbacks.",[458,459,460],"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":462},[463,464,465],{"id":199,"depth":113,"text":200},{"id":274,"depth":113,"text":275},{"id":370,"depth":113,"text":371},"One thread, one stack, and what \"blocking\" actually blocks.",{},"\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop\u002Fcall-stack",{"title":75,"description":466},"learn\u002Fen\u002Fcourses\u002Fevent-loop\u002F01.call-stack","BiJN8dMZjgvIkocYL4WlAg539TRcbZZHnuwy9Hi7GFg",{"id":473,"title":474,"access":6,"body":475,"description":897,"extension":17,"lang":20,"meta":898,"navigation":18,"order":113,"partial":15,"path":899,"seo":900,"stem":901,"__hash__":902},"lessons\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop\u002F02.task-queues.md","Tasks and microtasks",{"type":8,"value":476,"toc":891},[477,480,483,540,544,552,676,679,687,690,694,699,787,800,804,807,859,872,876,879,888],[79,478,474],{"id":479},"tasks-and-microtasks",[83,481,482],{},"There is not one queue. There are two, and they are drained differently.",[484,485,486,502],"table",{},[487,488,489],"thead",{},[490,491,492,496,499],"tr",{},[493,494,495],"th",{},"Queue",[493,497,498],{},"Sources",[493,500,501],{},"Drained",[503,504,505,523],"tbody",{},[490,506,507,511,520],{},[508,509,510],"td",{},"Task (macrotask)",[508,512,513,515,516,519],{},[93,514,289],{},", ",[93,517,518],{},"setInterval",", I\u002FO, events",[508,521,522],{},"One per loop iteration",[490,524,525,528,537],{},[508,526,527],{},"Microtask",[508,529,530,531,515,534],{},"Promise callbacks, ",[93,532,533],{},"queueMicrotask",[93,535,536],{},"MutationObserver",[508,538,539],{},"Completely, after every task",[197,541,543],{"id":542},"the-rule","The rule",[83,545,546,547,551],{},"After the stack empties, the event loop drains ",[548,549,550],"strong",{},"the entire microtask queue"," before\ntaking the next task. Microtasks added while draining are also processed in the same\npass.",[87,553,555],{"className":89,"code":554,"language":91,"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",[93,556,557,570,574,597,601,614,638,659,663],{"__ignoreMap":11},[96,558,559,561,563,565,568],{"class":98,"line":23},[96,560,304],{"class":109},[96,562,307],{"class":105},[96,564,310],{"class":109},[96,566,567],{"class":119},"'script start'",[96,569,316],{"class":109},[96,571,572],{"class":98,"line":113},[96,573,180],{"emptyLinePlaceholder":18},[96,575,576,578,580,582,584,586,588,591,593,595],{"class":98,"line":12},[96,577,289],{"class":105},[96,579,323],{"class":109},[96,581,326],{"class":101},[96,583,329],{"class":109},[96,585,307],{"class":105},[96,587,310],{"class":109},[96,589,590],{"class":119},"'timeout'",[96,592,339],{"class":109},[96,594,342],{"class":219},[96,596,316],{"class":109},[96,598,599],{"class":98,"line":128},[96,600,180],{"emptyLinePlaceholder":18},[96,602,603,606,609,612],{"class":98,"line":138},[96,604,605],{"class":219},"Promise",[96,607,608],{"class":109},".",[96,610,611],{"class":105},"resolve",[96,613,145],{"class":109},[96,615,616,619,622,624,626,628,630,632,635],{"class":98,"line":148},[96,617,618],{"class":109},"  .",[96,620,621],{"class":105},"then",[96,623,323],{"class":109},[96,625,326],{"class":101},[96,627,329],{"class":109},[96,629,307],{"class":105},[96,631,310],{"class":109},[96,633,634],{"class":119},"'promise 1'",[96,636,637],{"class":109},"))\n",[96,639,640,642,644,646,648,650,652,654,657],{"class":98,"line":153},[96,641,618],{"class":109},[96,643,621],{"class":105},[96,645,323],{"class":109},[96,647,326],{"class":101},[96,649,329],{"class":109},[96,651,307],{"class":105},[96,653,310],{"class":109},[96,655,656],{"class":119},"'promise 2'",[96,658,637],{"class":109},[96,660,661],{"class":98,"line":163},[96,662,180],{"emptyLinePlaceholder":18},[96,664,665,667,669,671,674],{"class":98,"line":172},[96,666,304],{"class":109},[96,668,307],{"class":105},[96,670,310],{"class":109},[96,672,673],{"class":119},"'script end'",[96,675,316],{"class":109},[83,677,678],{},"Output:",[87,680,685],{"className":681,"code":683,"language":684,"meta":11},[682],"language-text","script start\nscript end\npromise 1\npromise 2\ntimeout\n","text",[93,686,683],{"__ignoreMap":11},[83,688,689],{},"Both promise callbacks run before the timeout, even though the timeout was scheduled\nfirst. They are microtasks; the timeout is a task.",[197,691,693],{"id":692},"await-is-a-microtask-boundary","await is a microtask boundary",[83,695,696,698],{},[93,697,449],{}," suspends the function and schedules the remainder as a promise continuation:",[87,700,702],{"className":89,"code":701,"language":91,"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",[93,703,704,716,730,741,754,758,762,769,782],{"__ignoreMap":11},[96,705,706,708,711,714],{"class":98,"line":23},[96,707,38],{"class":101},[96,709,710],{"class":101}," function",[96,712,713],{"class":105}," run",[96,715,110],{"class":109},[96,717,718,721,723,725,728],{"class":98,"line":113},[96,719,720],{"class":109},"  console.",[96,722,307],{"class":105},[96,724,310],{"class":109},[96,726,727],{"class":119},"'a'",[96,729,316],{"class":109},[96,731,732,735,738],{"class":98,"line":12},[96,733,734],{"class":101},"  await",[96,736,737],{"class":219}," null",[96,739,740],{"class":264}," \u002F\u002F still a microtask, even awaiting a non-promise\n",[96,742,743,745,747,749,752],{"class":98,"line":128},[96,744,720],{"class":109},[96,746,307],{"class":105},[96,748,310],{"class":109},[96,750,751],{"class":119},"'c'",[96,753,316],{"class":109},[96,755,756],{"class":98,"line":138},[96,757,125],{"class":109},[96,759,760],{"class":98,"line":148},[96,761,180],{"emptyLinePlaceholder":18},[96,763,764,767],{"class":98,"line":153},[96,765,766],{"class":105},"run",[96,768,145],{"class":109},[96,770,771,773,775,777,780],{"class":98,"line":163},[96,772,304],{"class":109},[96,774,307],{"class":105},[96,776,310],{"class":109},[96,778,779],{"class":119},"'b'",[96,781,316],{"class":109},[96,783,784],{"class":98,"line":172},[96,785,786],{"class":264},"\u002F\u002F a, b, c\n",[83,788,789,792,793,795,796,799],{},[93,790,791],{},"await null"," does not skip the queue. Everything after the ",[93,794,449],{}," becomes a\nmicrotask, so the synchronous ",[93,797,798],{},"console.log('b')"," runs first.",[197,801,803],{"id":802},"starving-the-loop","Starving the loop",[83,805,806],{},"Because microtasks drain completely, a microtask that schedules another microtask\nforever prevents any task from ever running:",[87,808,810],{"className":89,"code":809,"language":91,"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",[93,811,812,821,838,842,849,854],{"__ignoreMap":11},[96,813,814,816,819],{"class":98,"line":23},[96,815,102],{"class":101},[96,817,818],{"class":105}," spin",[96,820,110],{"class":109},[96,822,823,826,828,830,833,835],{"class":98,"line":113},[96,824,825],{"class":219},"  Promise",[96,827,608],{"class":109},[96,829,611],{"class":105},[96,831,832],{"class":109},"().",[96,834,621],{"class":105},[96,836,837],{"class":109},"(spin)\n",[96,839,840],{"class":98,"line":12},[96,841,125],{"class":109},[96,843,844,847],{"class":98,"line":128},[96,845,846],{"class":105},"spin",[96,848,145],{"class":109},[96,850,851],{"class":98,"line":138},[96,852,853],{"class":264},"\u002F\u002F Timers never fire. Rendering never happens. The page is frozen —\n",[96,855,856],{"class":98,"line":148},[96,857,858],{"class":264},"\u002F\u002F but the CPU profile looks like idle promise work, not a busy loop.\n",[860,861,862],"danger",{},[83,863,864,865,868,869,871],{},"This is worse than a ",[93,866,867],{},"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",[93,870,289],{}," rather than promise recursion for anything that repeats indefinitely.",[197,873,875],{"id":874},"rendering","Rendering",[83,877,878],{},"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.",[880,881,882],"tip",{},[83,883,884,887],{},[93,885,886],{},"requestAnimationFrame"," callbacks run just before paint, after microtasks. That is\nthe correct place for visual updates, and the wrong place for anything expensive.",[458,889,890],{},"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":892},[893,894,895,896],{"id":542,"depth":113,"text":543},{"id":692,"depth":113,"text":693},{"id":802,"depth":113,"text":803},{"id":874,"depth":113,"text":875},"Two queues, different draining rules, and the ordering that follows.",{},"\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop\u002Ftask-queues",{"title":474,"description":897},"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":905},"\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":907},"\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":909},"\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":911},"\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":913},"\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":915},"\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":917,"title":5,"course":24,"description":918,"extension":919,"lang":20,"meta":920,"passingScore":921,"questions":922,"shuffle":18,"stem":1016,"__hash__":1017},"quizzes\u002Flearn\u002Fen\u002Fcourses\u002Fevent-loop\u002Fquiz.yml","Six questions on ordering, queues and blocking.","yml",{},70,[923,943,959,974,988,1002],{"id":924,"question":925,"type":926,"difficulty":927,"options":928,"correct":941,"explanation":942},"order-basic","What does this print? console.log('1'); setTimeout(() => console.log('3'), 0); console.log('2')","single","easy",[929,932,935,938],{"id":930,"text":931},"a","1, 2, 3",{"id":933,"text":934},"b","1, 3, 2",{"id":936,"text":937},"c","3, 1, 2",{"id":939,"text":940},"d","The order is not deterministic",[930],"setTimeout queues a task regardless of the delay. Tasks only run once the stack is empty, so both synchronous logs happen first.\n",{"id":944,"question":945,"type":946,"difficulty":947,"options":948,"correct":957,"explanation":958},"micro-vs-macro","Which of these schedule microtasks rather than tasks?","multiple","medium",[949,951,953,955],{"id":930,"text":950},"Promise.resolve().then(fn)",{"id":933,"text":952},"queueMicrotask(fn)",{"id":936,"text":954},"setTimeout(fn, 0)",{"id":939,"text":956},"The continuation after an await",[930,933,939],"Promise continuations, queueMicrotask and everything after an await are microtasks. setTimeout always queues a task, even with a zero delay.\n",{"id":960,"question":961,"type":926,"difficulty":962,"options":963,"correct":972,"explanation":973},"await-null","Does `await null` yield to the microtask queue?","hard",[964,966,968,970],{"id":930,"text":965},"No — awaiting a non-promise resolves synchronously",{"id":933,"text":967},"Yes — the rest of the function becomes a microtask either way",{"id":936,"text":969},"Only in strict mode",{"id":939,"text":971},"Only if the function was called from another async function",[933],"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":975,"question":976,"type":926,"difficulty":947,"options":977,"correct":986,"explanation":987},"drain-rule","How much of the microtask queue is drained between two tasks?",[978,980,982,984],{"id":930,"text":979},"One microtask",{"id":933,"text":981},"All of it, including microtasks added during the drain",{"id":936,"text":983},"All of it, but newly added ones wait for the next pass",{"id":939,"text":985},"As many as fit in the current frame budget",[933],"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":989,"question":990,"type":926,"difficulty":962,"options":991,"correct":1000,"explanation":1001},"starvation","Why is infinite promise recursion harder to diagnose than a while(true) loop?",[992,994,996,998],{"id":930,"text":993},"It only reproduces under load",{"id":933,"text":995},"The stack stays shallow and each microtask completes quickly",{"id":936,"text":997},"Browsers suppress errors inside promises",{"id":939,"text":999},"It does not actually block rendering",[933],"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":1003,"question":1004,"type":926,"difficulty":947,"options":1005,"correct":1014,"explanation":1015},"raf","When do requestAnimationFrame callbacks run?",[1006,1008,1010,1012],{"id":930,"text":1007},"Before microtasks are drained",{"id":933,"text":1009},"After microtasks, just before paint",{"id":936,"text":1011},"At the same priority as setTimeout(fn, 16)",{"id":939,"text":1013},"On a separate thread from the main loop",[933],"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":1019,"description":14,"draft":15,"estimatedMinutes":16,"extension":17,"featured":18,"icon":19,"lang":20,"level":21,"meta":1023,"navigation":18,"order":23,"path":24,"prerequisites":1024,"resources":1025,"seo":1027,"sku":32,"stem":33,"subjects":1028,"summary":36,"tags":1029,"updated":42,"__hash__":43},{"type":8,"value":1020,"toc":1021},[],{"title":11,"searchDepth":12,"depth":12,"links":1022},[],{},[],[1026],{"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":1031},"\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":1033},"\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>",1791742748870]