[{"data":1,"prerenderedAt":1219},["ShallowReactive",2],{"en-post-\u002Fen\u002Fjavascript-event-loop":3},{"id":4,"title":5,"body":6,"description":1206,"extension":1207,"meta":1208,"navigation":56,"path":1214,"seo":1215,"sitemap":1216,"stem":1217,"__hash__":1218},"blogEn\u002Fen\u002Fjavascript-event-loop.md","The JavaScript Event Loop Explained: How Microtasks and Macrotasks Are Ordered",{"type":7,"value":8,"toc":1190},"minimark",[9,14,18,148,157,165,180,183,187,193,200,203,289,291,295,298,325,328,336,339,370,372,376,381,475,481,484,488,500,601,607,628,630,634,637,694,797,803,833,835,839,843,850,871,878,1036,1043,1047,1060,1106,1110,1116,1118,1122,1180,1186],[10,11,13],"h2",{"id":12},"why-does-this-print-1-4-3-2","Why does this print 1 → 4 → 3 → 2?",[15,16,17],"p",{},"Let's start with a quiz.",[19,20,25],"pre",{"className":21,"code":22,"language":23,"meta":24,"style":24},"language-js shiki shiki-themes github-light github-dark","console.log(\"1\");\n\nsetTimeout(() => console.log(\"2\"), 0);\n\nPromise.resolve().then(() => console.log(\"3\"));\n\nconsole.log(\"4\");\n","js","",[26,27,28,51,58,90,95,129,134],"code",{"__ignoreMap":24},[29,30,33,37,41,44,48],"span",{"class":31,"line":32},"line",1,[29,34,36],{"class":35},"sVt8B","console.",[29,38,40],{"class":39},"sScJk","log",[29,42,43],{"class":35},"(",[29,45,47],{"class":46},"sZZnC","\"1\"",[29,49,50],{"class":35},");\n",[29,52,54],{"class":31,"line":53},2,[29,55,57],{"emptyLinePlaceholder":56},true,"\n",[29,59,61,64,67,71,74,76,78,81,84,88],{"class":31,"line":60},3,[29,62,63],{"class":39},"setTimeout",[29,65,66],{"class":35},"(() ",[29,68,70],{"class":69},"szBVR","=>",[29,72,73],{"class":35}," console.",[29,75,40],{"class":39},[29,77,43],{"class":35},[29,79,80],{"class":46},"\"2\"",[29,82,83],{"class":35},"), ",[29,85,87],{"class":86},"sj4cs","0",[29,89,50],{"class":35},[29,91,93],{"class":31,"line":92},4,[29,94,57],{"emptyLinePlaceholder":56},[29,96,98,101,104,107,110,113,115,117,119,121,123,126],{"class":31,"line":97},5,[29,99,100],{"class":86},"Promise",[29,102,103],{"class":35},".",[29,105,106],{"class":39},"resolve",[29,108,109],{"class":35},"().",[29,111,112],{"class":39},"then",[29,114,66],{"class":35},[29,116,70],{"class":69},[29,118,73],{"class":35},[29,120,40],{"class":39},[29,122,43],{"class":35},[29,124,125],{"class":46},"\"3\"",[29,127,128],{"class":35},"));\n",[29,130,132],{"class":31,"line":131},6,[29,133,57],{"emptyLinePlaceholder":56},[29,135,137,139,141,143,146],{"class":31,"line":136},7,[29,138,36],{"class":35},[29,140,40],{"class":39},[29,142,43],{"class":35},[29,144,145],{"class":46},"\"4\"",[29,147,50],{"class":35},[15,149,150,151,153,154,156],{},"The ",[26,152,63],{}," delay is ",[26,155,87],{},", so you might expect it to run right away. The actual output is:",[19,158,163],{"className":159,"code":161,"language":162},[160],"language-text","1\n4\n3\n2\n","text",[26,164,161],{"__ignoreMap":24},[15,166,167,170,171,174,175,179],{},[26,168,169],{},"Promise.then"," runs before ",[26,172,173],{},"setTimeout(0)",". To understand why, you need to know how the ",[176,177,178],"strong",{},"event loop"," works.",[181,182],"hr",{},[10,184,186],{"id":185},"what-is-the-event-loop","What is the event loop?",[188,189,190],"blockquote",{},[15,191,192],{},"The event loop is what lets single-threaded JavaScript handle asynchronous work: it decides the order between \"code to run now\" and \"callbacks to run later.\"",[15,194,195,196,199],{},"A JavaScript engine runs one piece of code at a time. It only looks like it's juggling timers, network requests, and clicks at once because the waiting is handed off to the browser (or Node.js), and the callbacks of finished work are ",[176,197,198],{},"lined up in queues"," and run one by one.",[15,201,202],{},"These are the pieces involved:",[204,205,206,222],"table",{},[207,208,209],"thead",{},[210,211,212,216,219],"tr",{},[213,214,215],"th",{},"Piece",[213,217,218],{},"Role",[213,220,221],{},"Examples",[223,224,225,237,252,269],"tbody",{},[210,226,227,231,234],{},[228,229,230],"td",{},"Call stack",[228,232,233],{},"Where currently running functions pile up",[228,235,236],{},"Regular function calls",[210,238,239,242,245],{},[228,240,241],{},"Web APIs \u002F runtime APIs",[228,243,244],{},"Handle slow work outside the engine",[228,246,247,248,251],{},"Timers, ",[26,249,250],{},"fetch",", DOM events",[210,253,254,257,260],{},[228,255,256],{},"Task queue (macrotasks)",[228,258,259],{},"Where callbacks of finished async work wait",[228,261,262,264,265,268],{},[26,263,63],{},", ",[26,266,267],{},"setInterval",", event handlers",[210,270,271,274,277],{},[228,272,273],{},"Microtask queue",[228,275,276],{},"Where higher-priority callbacks wait",[228,278,279,282,283,264,286],{},[26,280,281],{},"Promise.then\u002Fcatch\u002Ffinally",", code after ",[26,284,285],{},"await",[26,287,288],{},"queueMicrotask",[181,290],{},[10,292,294],{"id":293},"the-core-ordering-rule","The core ordering rule",[15,296,297],{},"The event loop repeats this cycle forever:",[299,300,301,309,315,322],"ol",{},[302,303,304,305,308],"li",{},"Take ",[176,306,307],{},"one task"," from the task queue and run it (at first, the whole script is one task).",[302,310,311,312,103],{},"When the call stack is empty, run microtasks ",[176,313,314],{},"until the microtask queue is completely empty",[302,316,317,318,321],{},"Repaint the screen if needed (rendering). ",[26,319,320],{},"requestAnimationFrame"," callbacks run in this step too.",[302,323,324],{},"Go back to step 1.",[15,326,327],{},"Step 2 is the key.",[329,330,331],"tip",{},[188,332,333],{},[15,334,335],{},"Tasks run one at a time. Microtasks run all at once, until the queue is empty.",[15,337,338],{},"Now replay the quiz:",[340,341,342,358,364],"ul",{},[302,343,344,345,348,349,351,352,354,355],{},"Script runs (a task) → prints ",[26,346,347],{},"1"," → the ",[26,350,63],{}," callback goes to the task queue → the ",[26,353,112],{}," callback goes to the microtask queue → prints ",[26,356,357],{},"4",[302,359,360,361],{},"Script ends, call stack is empty → drain the microtask queue → prints ",[26,362,363],{},"3",[302,365,366,367],{},"Next task → prints ",[26,368,369],{},"2",[181,371],{},[10,373,375],{"id":374},"practice-with-examples","Practice with examples",[377,378,380],"h3",{"id":379},"_1-microtasks-created-inside-a-task","1. Microtasks created inside a task",[19,382,384],{"className":21,"code":383,"language":23,"meta":24,"style":24},"setTimeout(() => {\n  console.log(\"timeout 1\");\n  Promise.resolve().then(() => console.log(\"micro in timeout 1\"));\n}, 0);\n\nsetTimeout(() => console.log(\"timeout 2\"), 0);\n",[26,385,386,397,411,439,448,452],{"__ignoreMap":24},[29,387,388,390,392,394],{"class":31,"line":32},[29,389,63],{"class":39},[29,391,66],{"class":35},[29,393,70],{"class":69},[29,395,396],{"class":35}," {\n",[29,398,399,402,404,406,409],{"class":31,"line":53},[29,400,401],{"class":35},"  console.",[29,403,40],{"class":39},[29,405,43],{"class":35},[29,407,408],{"class":46},"\"timeout 1\"",[29,410,50],{"class":35},[29,412,413,416,418,420,422,424,426,428,430,432,434,437],{"class":31,"line":60},[29,414,415],{"class":86},"  Promise",[29,417,103],{"class":35},[29,419,106],{"class":39},[29,421,109],{"class":35},[29,423,112],{"class":39},[29,425,66],{"class":35},[29,427,70],{"class":69},[29,429,73],{"class":35},[29,431,40],{"class":39},[29,433,43],{"class":35},[29,435,436],{"class":46},"\"micro in timeout 1\"",[29,438,128],{"class":35},[29,440,441,444,446],{"class":31,"line":92},[29,442,443],{"class":35},"}, ",[29,445,87],{"class":86},[29,447,50],{"class":35},[29,449,450],{"class":31,"line":97},[29,451,57],{"emptyLinePlaceholder":56},[29,453,454,456,458,460,462,464,466,469,471,473],{"class":31,"line":131},[29,455,63],{"class":39},[29,457,66],{"class":35},[29,459,70],{"class":69},[29,461,73],{"class":35},[29,463,40],{"class":39},[29,465,43],{"class":35},[29,467,468],{"class":46},"\"timeout 2\"",[29,470,83],{"class":35},[29,472,87],{"class":86},[29,474,50],{"class":35},[19,476,479],{"className":477,"code":478,"language":162},[160],"timeout 1\nmicro in timeout 1\ntimeout 2\n",[26,480,478],{"__ignoreMap":24},[15,482,483],{},"Even though both timers are already queued, the microtask created inside the first task runs right after that task finishes. Only then does the loop move on to the second task.",[377,485,487],{"id":486},"_2-async-await","2. async \u002F await",[15,489,490,491,493,494,496,497,103],{},"Code after ",[26,492,285],{}," is equivalent to a ",[26,495,112],{}," callback, which means it is ",[176,498,499],{},"scheduled as a microtask",[19,501,503],{"className":21,"code":502,"language":23,"meta":24,"style":24},"async function foo() {\n  console.log(\"foo start\");\n  await null;\n  console.log(\"foo end\");\n}\n\nconsole.log(\"script start\");\nfoo();\nconsole.log(\"script end\");\n",[26,504,505,519,532,543,556,561,565,578,587],{"__ignoreMap":24},[29,506,507,510,513,516],{"class":31,"line":32},[29,508,509],{"class":69},"async",[29,511,512],{"class":69}," function",[29,514,515],{"class":39}," foo",[29,517,518],{"class":35},"() {\n",[29,520,521,523,525,527,530],{"class":31,"line":53},[29,522,401],{"class":35},[29,524,40],{"class":39},[29,526,43],{"class":35},[29,528,529],{"class":46},"\"foo start\"",[29,531,50],{"class":35},[29,533,534,537,540],{"class":31,"line":60},[29,535,536],{"class":69},"  await",[29,538,539],{"class":86}," null",[29,541,542],{"class":35},";\n",[29,544,545,547,549,551,554],{"class":31,"line":92},[29,546,401],{"class":35},[29,548,40],{"class":39},[29,550,43],{"class":35},[29,552,553],{"class":46},"\"foo end\"",[29,555,50],{"class":35},[29,557,558],{"class":31,"line":97},[29,559,560],{"class":35},"}\n",[29,562,563],{"class":31,"line":131},[29,564,57],{"emptyLinePlaceholder":56},[29,566,567,569,571,573,576],{"class":31,"line":136},[29,568,36],{"class":35},[29,570,40],{"class":39},[29,572,43],{"class":35},[29,574,575],{"class":46},"\"script start\"",[29,577,50],{"class":35},[29,579,581,584],{"class":31,"line":580},8,[29,582,583],{"class":39},"foo",[29,585,586],{"class":35},"();\n",[29,588,590,592,594,596,599],{"class":31,"line":589},9,[29,591,36],{"class":35},[29,593,40],{"class":39},[29,595,43],{"class":35},[29,597,598],{"class":46},"\"script end\"",[29,600,50],{"class":35},[19,602,605],{"className":603,"code":604,"language":162},[160],"script start\nfoo start\nscript end\nfoo end\n",[26,606,604],{"__ignoreMap":24},[15,608,609,610,612,613,616,617,619,620,623,624,627],{},"An ",[26,611,509],{}," function runs ",[176,614,615],{},"synchronously"," until its first ",[26,618,285],{},". That's why ",[26,621,622],{},"foo start"," prints before ",[26,625,626],{},"script end",". It's easy to assume an async function is asynchronous from the very first line, but it isn't.",[181,629],{},[10,631,633],{"id":632},"browser-vs-nodejs","Browser vs Node.js",[15,635,636],{},"Node.js also uses an event loop, but it's built on libuv, splits the loop into more phases, and has APIs browsers don't.",[204,638,639,651],{},[207,640,641],{},[210,642,643,645,648],{},[213,644],{},[213,646,647],{},"Browser",[213,649,650],{},"Node.js",[223,652,653,667,681],{},[210,654,655,658,664],{},[228,656,657],{},"Rendering step",[228,659,660,661,663],{},"Yes (",[26,662,320],{},")",[228,665,666],{},"No",[210,668,669,672,675],{},[228,670,671],{},"Extra queue",[228,673,674],{},"-",[228,676,677,680],{},[26,678,679],{},"process.nextTick"," queue (runs before Promises)",[210,682,683,686,688],{},[228,684,685],{},"Extra API",[228,687,674],{},[228,689,690,693],{},[26,691,692],{},"setImmediate"," (runs in the check phase)",[19,695,697],{"className":21,"code":696,"language":23,"meta":24,"style":24},"\u002F\u002F Node.js, CommonJS module\nsetTimeout(() => console.log(\"timeout\"), 0);\nsetImmediate(() => console.log(\"immediate\"));\nprocess.nextTick(() => console.log(\"nextTick\"));\nPromise.resolve().then(() => console.log(\"promise\"));\n",[26,698,699,705,728,747,770],{"__ignoreMap":24},[29,700,701],{"class":31,"line":32},[29,702,704],{"class":703},"sJ8bj","\u002F\u002F Node.js, CommonJS module\n",[29,706,707,709,711,713,715,717,719,722,724,726],{"class":31,"line":53},[29,708,63],{"class":39},[29,710,66],{"class":35},[29,712,70],{"class":69},[29,714,73],{"class":35},[29,716,40],{"class":39},[29,718,43],{"class":35},[29,720,721],{"class":46},"\"timeout\"",[29,723,83],{"class":35},[29,725,87],{"class":86},[29,727,50],{"class":35},[29,729,730,732,734,736,738,740,742,745],{"class":31,"line":60},[29,731,692],{"class":39},[29,733,66],{"class":35},[29,735,70],{"class":69},[29,737,73],{"class":35},[29,739,40],{"class":39},[29,741,43],{"class":35},[29,743,744],{"class":46},"\"immediate\"",[29,746,128],{"class":35},[29,748,749,752,755,757,759,761,763,765,768],{"class":31,"line":92},[29,750,751],{"class":35},"process.",[29,753,754],{"class":39},"nextTick",[29,756,66],{"class":35},[29,758,70],{"class":69},[29,760,73],{"class":35},[29,762,40],{"class":39},[29,764,43],{"class":35},[29,766,767],{"class":46},"\"nextTick\"",[29,769,128],{"class":35},[29,771,772,774,776,778,780,782,784,786,788,790,792,795],{"class":31,"line":97},[29,773,100],{"class":86},[29,775,103],{"class":35},[29,777,106],{"class":39},[29,779,109],{"class":35},[29,781,112],{"class":39},[29,783,66],{"class":35},[29,785,70],{"class":69},[29,787,73],{"class":35},[29,789,40],{"class":39},[29,791,43],{"class":35},[29,793,794],{"class":46},"\"promise\"",[29,796,128],{"class":35},[19,798,801],{"className":799,"code":800,"language":162},[160],"nextTick\npromise\ntimeout \u002F immediate (their order can change from run to run)\n",[26,802,800],{"__ignoreMap":24},[804,805,806],"warning",{},[188,807,808],{},[15,809,810,811,813,814,816,817,83,820,822,823,826,827,830,831,103],{},"In the main module, the order of ",[26,812,173],{}," and ",[26,815,692],{}," is not guaranteed. Inside an I\u002FO callback (for example, the callback of ",[26,818,819],{},"fs.readFile",[26,821,692],{}," always runs first. And in ES modules (",[26,824,825],{},".mjs","), top-level code already runs inside a microtask, so ",[26,828,829],{},"promise"," can print before ",[26,832,754],{},[181,834],{},[10,836,838],{"id":837},"problems-youll-hit-in-real-code","Problems you'll hit in real code",[377,840,842],{"id":841},"_1-heavy-synchronous-work-freezes-the-screen","1. Heavy synchronous work freezes the screen",[15,844,845,846,849],{},"Rendering only happens ",[176,847,848],{},"between"," tasks. If one task takes a long time, clicks, scrolling, and screen updates all freeze until it's done.",[19,851,853],{"className":21,"code":852,"language":23,"meta":24,"style":24},"\u002F\u002F ❌ Processing 100,000 items in one go freezes the UI\nitems.forEach(processItem);\n",[26,854,855,860],{"__ignoreMap":24},[29,856,857],{"class":31,"line":32},[29,858,859],{"class":703},"\u002F\u002F ❌ Processing 100,000 items in one go freezes the UI\n",[29,861,862,865,868],{"class":31,"line":53},[29,863,864],{"class":35},"items.",[29,866,867],{"class":39},"forEach",[29,869,870],{"class":35},"(processItem);\n",[15,872,873,874,877],{},"Split the work into chunks and create ",[176,875,876],{},"task boundaries"," along the way so the browser can breathe. Briefly handing the main thread back like this is called yielding.",[19,879,881],{"className":21,"code":880,"language":23,"meta":24,"style":24},"\u002F\u002F ✅ Hand off to a new task every so often so rendering and input can run\nconst yieldToMain = () => new Promise((resolve) => setTimeout(resolve, 0));\n\nasync function processAll(items) {\n  for (let i = 0; i \u003C items.length; i++) {\n    processItem(items[i]);\n    if (i % 500 === 0) await yieldToMain();\n  }\n}\n",[26,882,883,888,931,935,952,992,1000,1027,1032],{"__ignoreMap":24},[29,884,885],{"class":31,"line":32},[29,886,887],{"class":703},"\u002F\u002F ✅ Hand off to a new task every so often so rendering and input can run\n",[29,889,890,893,896,899,902,904,907,910,913,916,919,921,924,927,929],{"class":31,"line":53},[29,891,892],{"class":69},"const",[29,894,895],{"class":39}," yieldToMain",[29,897,898],{"class":69}," =",[29,900,901],{"class":35}," () ",[29,903,70],{"class":69},[29,905,906],{"class":69}," new",[29,908,909],{"class":86}," Promise",[29,911,912],{"class":35},"((",[29,914,106],{"class":915},"s4XuR",[29,917,918],{"class":35},") ",[29,920,70],{"class":69},[29,922,923],{"class":39}," setTimeout",[29,925,926],{"class":35},"(resolve, ",[29,928,87],{"class":86},[29,930,128],{"class":35},[29,932,933],{"class":31,"line":60},[29,934,57],{"emptyLinePlaceholder":56},[29,936,937,939,941,944,946,949],{"class":31,"line":92},[29,938,509],{"class":69},[29,940,512],{"class":69},[29,942,943],{"class":39}," processAll",[29,945,43],{"class":35},[29,947,948],{"class":915},"items",[29,950,951],{"class":35},") {\n",[29,953,954,957,960,963,966,969,972,975,978,981,984,987,990],{"class":31,"line":97},[29,955,956],{"class":69},"  for",[29,958,959],{"class":35}," (",[29,961,962],{"class":69},"let",[29,964,965],{"class":35}," i ",[29,967,968],{"class":69},"=",[29,970,971],{"class":86}," 0",[29,973,974],{"class":35},"; i ",[29,976,977],{"class":69},"\u003C",[29,979,980],{"class":35}," items.",[29,982,983],{"class":86},"length",[29,985,986],{"class":35},"; i",[29,988,989],{"class":69},"++",[29,991,951],{"class":35},[29,993,994,997],{"class":31,"line":131},[29,995,996],{"class":39},"    processItem",[29,998,999],{"class":35},"(items[i]);\n",[29,1001,1002,1005,1008,1011,1014,1017,1019,1021,1023,1025],{"class":31,"line":136},[29,1003,1004],{"class":69},"    if",[29,1006,1007],{"class":35}," (i ",[29,1009,1010],{"class":69},"%",[29,1012,1013],{"class":86}," 500",[29,1015,1016],{"class":69}," ===",[29,1018,971],{"class":86},[29,1020,918],{"class":35},[29,1022,285],{"class":69},[29,1024,895],{"class":39},[29,1026,586],{"class":35},[29,1028,1029],{"class":31,"line":580},[29,1030,1031],{"class":35},"  }\n",[29,1033,1034],{"class":31,"line":589},[29,1035,560],{"class":35},[15,1037,1038,1039,1042],{},"Recent Chromium-based browsers provide ",[26,1040,1041],{},"scheduler.yield()"," for exactly this. Check for support and use it where available.",[377,1044,1046],{"id":1045},"_2-microtasks-dont-yield","2. Microtasks don't yield",[15,1048,1049,1050,1052,1053,1056,1057,103],{},"If you swap ",[26,1051,63],{}," for ",[26,1054,1055],{},"Promise.resolve()"," in the code above, it stops working. Microtasks keep running until the queue is empty, so rendering never gets a chance in between. If microtasks keep scheduling new microtasks, the page freezes completely, just like ",[26,1058,1059],{},"while (true)",[19,1061,1063],{"className":21,"code":1062,"language":23,"meta":24,"style":24},"\u002F\u002F ❌ Rendering never happens\nfunction loop() {\n  Promise.resolve().then(loop);\n}\nloop();\n",[26,1064,1065,1070,1080,1095,1099],{"__ignoreMap":24},[29,1066,1067],{"class":31,"line":32},[29,1068,1069],{"class":703},"\u002F\u002F ❌ Rendering never happens\n",[29,1071,1072,1075,1078],{"class":31,"line":53},[29,1073,1074],{"class":69},"function",[29,1076,1077],{"class":39}," loop",[29,1079,518],{"class":35},[29,1081,1082,1084,1086,1088,1090,1092],{"class":31,"line":60},[29,1083,415],{"class":86},[29,1085,103],{"class":35},[29,1087,106],{"class":39},[29,1089,109],{"class":35},[29,1091,112],{"class":39},[29,1093,1094],{"class":35},"(loop);\n",[29,1096,1097],{"class":31,"line":92},[29,1098,560],{"class":35},[29,1100,1101,1104],{"class":31,"line":97},[29,1102,1103],{"class":39},"loop",[29,1105,586],{"class":35},[377,1107,1109],{"id":1108},"_3-0ms-doesnt-mean-now","3. \"0ms\" doesn't mean \"now\"",[15,1111,1112,1115],{},[26,1113,1114],{},"setTimeout(fn, 0)"," means \"put this in the task queue after at least 0ms.\" It only runs after every task and microtask ahead of it is done, and browsers may raise the minimum delay of nested timers to 4ms. Don't rely on it for precise timing.",[181,1117],{},[10,1119,1121],{"id":1120},"summary-why-this-is-worth-knowing","Summary: why this is worth knowing",[204,1123,1124,1134],{},[207,1125,1126],{},[210,1127,1128,1131],{},[213,1129,1130],{},"What you see",[213,1132,1133],{},"The event loop explanation",[223,1135,1136,1149,1162,1170],{},[210,1137,1138,1146],{},[228,1139,1140,1141,1143,1144],{},"A ",[26,1142,112],{}," callback runs before ",[26,1145,173],{},[228,1147,1148],{},"Microtasks run before the next task",[210,1150,1151,1157],{},[228,1152,1153,1154,1156],{},"The top of an ",[26,1155,509],{}," function runs immediately",[228,1158,1159,1160],{},"It's synchronous until the first ",[26,1161,285],{},[210,1163,1164,1167],{},[228,1165,1166],{},"The screen freezes during a big loop",[228,1168,1169],{},"One task is blocking the chance to render",[210,1171,1172,1177],{},[228,1173,1174,1175],{},"Still frozen after splitting with ",[26,1176,100],{},[228,1178,1179],{},"All microtasks run before rendering",[15,1181,1182,1183],{},"Once you understand the event loop, you spend far less time on \"why are these logs in this order?\", and you can quickly pin down why a loading spinner won't spin or input feels laggy. When async code doesn't behave the way you expect, start by asking: ",[176,1184,1185],{},"\"Is this callback a task or a microtask?\"",[1187,1188,1189],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":24,"searchDepth":53,"depth":53,"links":1191},[1192,1193,1194,1195,1199,1200,1205],{"id":12,"depth":53,"text":13},{"id":185,"depth":53,"text":186},{"id":293,"depth":53,"text":294},{"id":374,"depth":53,"text":375,"children":1196},[1197,1198],{"id":379,"depth":60,"text":380},{"id":486,"depth":60,"text":487},{"id":632,"depth":53,"text":633},{"id":837,"depth":53,"text":838,"children":1201},[1202,1203,1204],{"id":841,"depth":60,"text":842},{"id":1045,"depth":60,"text":1046},{"id":1108,"depth":60,"text":1109},{"id":1120,"depth":53,"text":1121},"Why does Promise.then run before setTimeout(0)? A walkthrough of the call stack, task queue, and microtask queue with runnable examples, plus how browsers and Node.js differ and how to keep long work from freezing the UI.","md",{"date":1209,"field":1210,"tags":1211},"2026.10.08","concepts",[1212,1213],"javascript","nodejs","\u002Fen\u002Fjavascript-event-loop",{"title":5,"description":1206},{"loc":1214},"en\u002Fjavascript-event-loop","3w7zSJGahVlQq40z7xvx0wJWW80JtVnEe1yU7n5XFos",1791459767455]