[{"data":1,"prerenderedAt":3620},["ShallowReactive",2],{"page-\u002Fjs\u002F15-callbacks-and-the-event-loop":3},{"id":4,"title":5,"body":6,"description":195,"extension":3614,"meta":3615,"navigation":34,"path":3616,"seo":3617,"stem":3618,"__hash__":3619},"content\u002Fjs\u002F15-callbacks-and-the-event-loop.md","15 — Callbacks & the Event Loop",{"type":7,"value":8,"toc":3584},"minimark",[9,13,91,180,374,599,832,1048,1203,1402,1499,1685,1892,2084,2261,2501,2666,2738,2936,3174,3280,3580],[10,11,5],"h1",{"id":12},"_15-callbacks-the-event-loop",[14,15,16,21,63],"question-wrapper",{},[17,18,20],"h3",{"id":19},"q1-what-does-it-actually-mean-that-javascript-is-single-threaded-in-terms-of-the-call-stack-and-the-event-loop","Q1. What does it actually mean that \"JavaScript is single-threaded,\" in terms of the call stack and the event loop?",[22,23,26,37,51,57],"ul",{"className":24},[25],"contains-task-list",[27,28,31,36],"li",{"className":29},[30],"task-list-item",[32,33],"input",{"disabled":34,"type":35},true,"checkbox"," JS can only execute one function at a time on its single call stack; the event loop, task queues, and the browser\u002FNode runtime's own APIs work alongside that one thread to schedule async callbacks, without ever running two pieces of JS code simultaneously",[27,38,40,42,43,47,48],{"className":39},[30],[32,41],{"disabled":34,"type":35}," JS spawns a new OS thread for every async operation, such as ",[44,45,46],"code",{},"setTimeout"," or ",[44,49,50],{},"fetch",[27,52,54,56],{"className":53},[30],[32,55],{"disabled":34,"type":35}," Single-threaded means JavaScript cannot use callbacks at all",[27,58,60,62],{"className":59},[30],[32,61],{"disabled":34,"type":35}," Single-threaded only describes Node.js; browsers run JS on multiple threads",[64,65,66,70,78],"details",{},[67,68,69],"summary",{},"Show Answer",[71,72,73,77],"p",{},[74,75,76],"strong",{},"Answer:"," A — JS can only execute one function at a time on its single call stack; the event loop, task queues, and the browser\u002FNode runtime's own APIs work alongside that one thread to schedule async callbacks, without ever running two pieces of JS code simultaneously",[71,79,80,83,84,87,88,90],{},[74,81,82],{},"Explanation:"," There is exactly one call stack per JS realm, and only one frame ever executes at a time. Timers, network requests, and file I\u002FO are handled by the surrounding environment (browser Web APIs, or Node's ",[44,85,86],{},"libuv","), which may internally use threads, but the JS callback that eventually reports the result always gets funneled back onto the single call stack, one at a time, via the event loop. Option B is a common misconception — ",[44,89,46],{}," itself doesn't spawn a thread for your callback; only some underlying runtime plumbing might. Option C is nonsensical. Option D is wrong — the main JS thread in a browser tab is just as single-threaded as Node's.",[14,92,93,101,140],{},[17,94,96,97,100],{"id":95},"q2-which-of-the-following-is-classified-as-a-microtask-rather-than-a-macrotask","Q2. Which of the following is classified as a ",[74,98,99],{},"microtask"," rather than a macrotask?",[22,102,104,113,121,130],{"className":103},[25],[27,105,107,109,110,112],{"className":106},[30],[32,108],{"disabled":34,"type":35}," A ",[44,111,46],{}," callback",[27,114,116,109,118,112],{"className":115},[30],[32,117],{"disabled":34,"type":35},[44,119,120],{},"setInterval",[27,122,124,126,127,112],{"className":123},[30],[32,125],{"disabled":34,"type":35}," A Promise's ",[44,128,129],{},".then()",[27,131,133,135,136,139],{"className":132},[30],[32,134],{"disabled":34,"type":35}," A UI ",[44,137,138],{},"click"," event handler callback",[64,141,142,144,151],{},[67,143,69],{},[71,145,146,148,149,112],{},[74,147,76],{}," C — A Promise's ",[44,150,129],{},[71,152,153,155,156,159,160,159,163,166,167,170,171,173,174,176,177,179],{},[74,154,82],{}," The microtask queue holds promise reaction callbacks (",[44,157,158],{},".then","\u002F",[44,161,162],{},".catch",[44,164,165],{},".finally",") and anything scheduled with ",[44,168,169],{},"queueMicrotask",". Timers (",[44,172,46],{},", ",[44,175,120],{},"), I\u002FO completions, and UI events like ",[44,178,138],{}," are all macrotasks (sometimes just called \"tasks\"). This distinction matters because the event loop always fully drains the microtask queue between one macrotask and the next — a rule tested throughout this quiz.",[14,181,183,187,300,336],{"language":182},"javascript",[17,184,186],{"id":185},"q3-what-does-this-code-log-and-in-what-order","Q3. What does this code log, and in what order?",[188,189,190],"code-wrapper",{"language":182},[191,192,196],"pre",{"className":193,"code":194,"language":182,"meta":195,"style":195},"language-javascript shiki shiki-themes github-light github-dark","console.log(\"start\");\nsetTimeout(() => console.log(\"timeout\"), 0);\nPromise.resolve().then(() => console.log(\"promise\"));\nconsole.log(\"end\");\n","",[44,197,198,221,252,286],{"__ignoreMap":195},[199,200,203,207,211,214,218],"span",{"class":201,"line":202},"line",1,[199,204,206],{"class":205},"ssxIu","console.",[199,208,210],{"class":209},"sIsaT","log",[199,212,213],{"class":205},"(",[199,215,217],{"class":216},"sJ6F3","\"start\"",[199,219,220],{"class":205},");\n",[199,222,224,226,229,233,236,238,240,243,246,250],{"class":201,"line":223},2,[199,225,46],{"class":209},[199,227,228],{"class":205},"(() ",[199,230,232],{"class":231},"svdQ7","=>",[199,234,235],{"class":205}," console.",[199,237,210],{"class":209},[199,239,213],{"class":205},[199,241,242],{"class":216},"\"timeout\"",[199,244,245],{"class":205},"), ",[199,247,249],{"class":248},"snvgF","0",[199,251,220],{"class":205},[199,253,255,258,261,264,267,270,272,274,276,278,280,283],{"class":201,"line":254},3,[199,256,257],{"class":248},"Promise",[199,259,260],{"class":205},".",[199,262,263],{"class":209},"resolve",[199,265,266],{"class":205},"().",[199,268,269],{"class":209},"then",[199,271,228],{"class":205},[199,273,232],{"class":231},[199,275,235],{"class":205},[199,277,210],{"class":209},[199,279,213],{"class":205},[199,281,282],{"class":216},"\"promise\"",[199,284,285],{"class":205},"));\n",[199,287,289,291,293,295,298],{"class":201,"line":288},4,[199,290,206],{"class":205},[199,292,210],{"class":209},[199,294,213],{"class":205},[199,296,297],{"class":216},"\"end\"",[199,299,220],{"class":205},[22,301,303,312,320,328],{"className":302},[25],[27,304,306,308,309],{"className":305},[30],[32,307],{"disabled":34,"type":35}," ",[44,310,311],{},"start, promise, end, timeout",[27,313,315,308,317],{"className":314},[30],[32,316],{"disabled":34,"type":35},[44,318,319],{},"start, end, timeout, promise",[27,321,323,308,325],{"className":322},[30],[32,324],{"disabled":34,"type":35},[44,326,327],{},"start, promise, timeout, end",[27,329,331,308,333],{"className":330},[30],[32,332],{"disabled":34,"type":35},[44,334,335],{},"start, end, promise, timeout",[64,337,338,340,347],{},[67,339,69],{},[71,341,342,344,345],{},[74,343,76],{}," D — ",[44,346,335],{},[71,348,349,351,352,355,356,359,360,362,363,366,367,370,371,373],{},[74,350,82],{}," All synchronous code runs first to completion (",[44,353,354],{},"start",", then ",[44,357,358],{},"end","), regardless of what async work was scheduled in between. Once the call stack is empty, the event loop drains the microtask queue completely before touching the macrotask queue, so the resolved promise's ",[44,361,158],{}," callback (",[44,364,365],{},"promise",") runs next. Only after the microtask queue is empty does the loop pick up the next macrotask, running the timeout callback (",[44,368,369],{},"timeout",") last. Option A wrongly assumes an already-resolved promise interrupts synchronous code — it never does, ",[44,372,158],{}," callbacks are always deferred at least to the microtask queue. Option B reverses microtask\u002Fmacrotask priority.",[14,375,376,380,509,544],{"language":182},[17,377,379],{"id":378},"q4-what-does-this-code-log-and-in-what-order","Q4. What does this code log, and in what order?",[188,381,382],{"language":182},[191,383,385],{"className":193,"code":384,"language":182,"meta":195,"style":195},"console.log(\"A\");\n\nsetTimeout(() => console.log(\"B\"), 0);\n\nPromise.resolve()\n  .then(() => console.log(\"C\"))\n  .then(() => console.log(\"D\"));\n\nconsole.log(\"E\");\n",[44,386,387,400,405,428,432,444,468,490,495],{"__ignoreMap":195},[199,388,389,391,393,395,398],{"class":201,"line":202},[199,390,206],{"class":205},[199,392,210],{"class":209},[199,394,213],{"class":205},[199,396,397],{"class":216},"\"A\"",[199,399,220],{"class":205},[199,401,402],{"class":201,"line":223},[199,403,404],{"emptyLinePlaceholder":34},"\n",[199,406,407,409,411,413,415,417,419,422,424,426],{"class":201,"line":254},[199,408,46],{"class":209},[199,410,228],{"class":205},[199,412,232],{"class":231},[199,414,235],{"class":205},[199,416,210],{"class":209},[199,418,213],{"class":205},[199,420,421],{"class":216},"\"B\"",[199,423,245],{"class":205},[199,425,249],{"class":248},[199,427,220],{"class":205},[199,429,430],{"class":201,"line":288},[199,431,404],{"emptyLinePlaceholder":34},[199,433,435,437,439,441],{"class":201,"line":434},5,[199,436,257],{"class":248},[199,438,260],{"class":205},[199,440,263],{"class":209},[199,442,443],{"class":205},"()\n",[199,445,447,450,452,454,456,458,460,462,465],{"class":201,"line":446},6,[199,448,449],{"class":205},"  .",[199,451,269],{"class":209},[199,453,228],{"class":205},[199,455,232],{"class":231},[199,457,235],{"class":205},[199,459,210],{"class":209},[199,461,213],{"class":205},[199,463,464],{"class":216},"\"C\"",[199,466,467],{"class":205},"))\n",[199,469,471,473,475,477,479,481,483,485,488],{"class":201,"line":470},7,[199,472,449],{"class":205},[199,474,269],{"class":209},[199,476,228],{"class":205},[199,478,232],{"class":231},[199,480,235],{"class":205},[199,482,210],{"class":209},[199,484,213],{"class":205},[199,486,487],{"class":216},"\"D\"",[199,489,285],{"class":205},[199,491,493],{"class":201,"line":492},8,[199,494,404],{"emptyLinePlaceholder":34},[199,496,498,500,502,504,507],{"class":201,"line":497},9,[199,499,206],{"class":205},[199,501,210],{"class":209},[199,503,213],{"class":205},[199,505,506],{"class":216},"\"E\"",[199,508,220],{"class":205},[22,510,512,520,528,536],{"className":511},[25],[27,513,515,308,517],{"className":514},[30],[32,516],{"disabled":34,"type":35},[44,518,519],{},"A, E, B, C, D",[27,521,523,308,525],{"className":522},[30],[32,524],{"disabled":34,"type":35},[44,526,527],{},"A, E, C, D, B",[27,529,531,308,533],{"className":530},[30],[32,532],{"disabled":34,"type":35},[44,534,535],{},"A, C, D, E, B",[27,537,539,308,541],{"className":538},[30],[32,540],{"disabled":34,"type":35},[44,542,543],{},"A, E, C, B, D",[64,545,546,548,555],{},[67,547,69],{},[71,549,550,552,553],{},[74,551,76],{}," B — ",[44,554,527],{},[71,556,557,308,559,562,563,173,566,569,570,572,573,576,577,308,581,583,584,587,588,591,592,594,595,598],{},[74,558,82],{},[74,560,561],{},"Debug:"," synchronous code runs first (",[44,564,565],{},"A",[44,567,568],{},"E","). The first ",[44,571,158],{}," then logs ",[44,574,575],{},"C",", and in the process of resolving it, the ",[578,579,580],"em",{},"second",[44,582,158],{}," gets queued as a brand-new microtask — but the event loop doesn't care that it was queued \"late\"; it keeps draining the microtask queue as long as anything is in it, so ",[44,585,586],{},"D"," runs before the loop is even allowed to consider the next macrotask. Only once the microtask queue is truly empty does ",[44,589,590],{},"B"," (the timeout) finally run. Option D wrongly inserts the macrotask between the two chained ",[44,593,158],{}," calls, which would only happen if microtasks queued ",[578,596,597],{},"during"," draining were deferred to the next loop turn — they are not.",[14,600,601,605,734,770],{"language":182},[17,602,604],{"id":603},"q5-what-does-this-code-log-and-in-what-order","Q5. What does this code log, and in what order?",[188,606,607],{"language":182},[191,608,610],{"className":193,"code":609,"language":182,"meta":195,"style":195},"function first() {\n  console.log(\"first\");\n}\nfunction second() {\n  setTimeout(() => console.log(\"second\"), 0);\n}\nfunction third() {\n  console.log(\"third\");\n}\n\nfirst();\nsecond();\nthird();\n",[44,611,612,623,637,642,651,675,679,688,701,705,710,719,726],{"__ignoreMap":195},[199,613,614,617,620],{"class":201,"line":202},[199,615,616],{"class":231},"function",[199,618,619],{"class":209}," first",[199,621,622],{"class":205},"() {\n",[199,624,625,628,630,632,635],{"class":201,"line":223},[199,626,627],{"class":205},"  console.",[199,629,210],{"class":209},[199,631,213],{"class":205},[199,633,634],{"class":216},"\"first\"",[199,636,220],{"class":205},[199,638,639],{"class":201,"line":254},[199,640,641],{"class":205},"}\n",[199,643,644,646,649],{"class":201,"line":288},[199,645,616],{"class":231},[199,647,648],{"class":209}," second",[199,650,622],{"class":205},[199,652,653,656,658,660,662,664,666,669,671,673],{"class":201,"line":434},[199,654,655],{"class":209},"  setTimeout",[199,657,228],{"class":205},[199,659,232],{"class":231},[199,661,235],{"class":205},[199,663,210],{"class":209},[199,665,213],{"class":205},[199,667,668],{"class":216},"\"second\"",[199,670,245],{"class":205},[199,672,249],{"class":248},[199,674,220],{"class":205},[199,676,677],{"class":201,"line":446},[199,678,641],{"class":205},[199,680,681,683,686],{"class":201,"line":470},[199,682,616],{"class":231},[199,684,685],{"class":209}," third",[199,687,622],{"class":205},[199,689,690,692,694,696,699],{"class":201,"line":492},[199,691,627],{"class":205},[199,693,210],{"class":209},[199,695,213],{"class":205},[199,697,698],{"class":216},"\"third\"",[199,700,220],{"class":205},[199,702,703],{"class":201,"line":497},[199,704,641],{"class":205},[199,706,708],{"class":201,"line":707},10,[199,709,404],{"emptyLinePlaceholder":34},[199,711,713,716],{"class":201,"line":712},11,[199,714,715],{"class":209},"first",[199,717,718],{"class":205},"();\n",[199,720,722,724],{"class":201,"line":721},12,[199,723,580],{"class":209},[199,725,718],{"class":205},[199,727,729,732],{"class":201,"line":728},13,[199,730,731],{"class":209},"third",[199,733,718],{"class":205},[22,735,737,745,753,761],{"className":736},[25],[27,738,740,308,742],{"className":739},[30],[32,741],{"disabled":34,"type":35},[44,743,744],{},"first, second, third",[27,746,748,308,750],{"className":747},[30],[32,749],{"disabled":34,"type":35},[44,751,752],{},"second, first, third",[27,754,756,308,758],{"className":755},[30],[32,757],{"disabled":34,"type":35},[44,759,760],{},"first, third, second",[27,762,764,308,766,769],{"className":763},[30],[32,765],{"disabled":34,"type":35},[44,767,768],{},"first, third",", then a thrown error",[64,771,772,774,781],{},[67,773,69],{},[71,775,776,778,779],{},[74,777,76],{}," C — ",[44,780,760],{},[71,782,783,308,785,787,788,791,792,795,796,798,799,801,802,804,805,173,808,173,810,813,814,355,816,818,819,821,822,824,825,827,828,831],{},[74,784,82],{},[74,786,561],{}," calling ",[44,789,790],{},"second()"," doesn't log anything itself — it only ",[578,793,794],{},"registers"," a macrotask via ",[44,797,46],{},"; the string ",[44,800,668],{}," lives inside the deferred arrow function, not in ",[44,803,790],{},"'s own body. So the synchronous call order (",[44,806,807],{},"first()",[44,809,790],{},[44,811,812],{},"third()",") produces ",[44,815,715],{},[44,817,731],{}," (since ",[44,820,790],{}," produces no immediate output), and only after the stack is empty does the deferred callback finally run, logging ",[44,823,580],{}," last. The trap here is conflating \"the function named ",[44,826,580],{}," was called second\" with \"the value ",[44,829,830],{},"\\\"second\\\""," logs second\" — they're unrelated once a timer is involved.",[14,833,834,838,987,1022],{"language":182},[17,835,837],{"id":836},"q6-what-does-this-code-log-and-in-what-order","Q6. What does this code log, and in what order?",[188,839,840],{"language":182},[191,841,843],{"className":193,"code":842,"language":182,"meta":195,"style":195},"function loopMicrotasks(n) {\n  if (n \u003C= 0) return;\n  queueMicrotask(() => {\n    console.log(\"microtask\", n);\n    loopMicrotasks(n - 1);\n  });\n}\n\nconsole.log(\"sync\");\nloopMicrotasks(3);\nsetTimeout(() => console.log(\"timeout\"), 0);\n",[44,844,845,861,884,896,911,927,932,936,940,953,965],{"__ignoreMap":195},[199,846,847,849,852,854,858],{"class":201,"line":202},[199,848,616],{"class":231},[199,850,851],{"class":209}," loopMicrotasks",[199,853,213],{"class":205},[199,855,857],{"class":856},"sCrzJ","n",[199,859,860],{"class":205},") {\n",[199,862,863,866,869,872,875,878,881],{"class":201,"line":223},[199,864,865],{"class":231},"  if",[199,867,868],{"class":205}," (n ",[199,870,871],{"class":231},"\u003C=",[199,873,874],{"class":248}," 0",[199,876,877],{"class":205},") ",[199,879,880],{"class":231},"return",[199,882,883],{"class":205},";\n",[199,885,886,889,891,893],{"class":201,"line":254},[199,887,888],{"class":209},"  queueMicrotask",[199,890,228],{"class":205},[199,892,232],{"class":231},[199,894,895],{"class":205}," {\n",[199,897,898,901,903,905,908],{"class":201,"line":288},[199,899,900],{"class":205},"    console.",[199,902,210],{"class":209},[199,904,213],{"class":205},[199,906,907],{"class":216},"\"microtask\"",[199,909,910],{"class":205},", n);\n",[199,912,913,916,919,922,925],{"class":201,"line":434},[199,914,915],{"class":209},"    loopMicrotasks",[199,917,918],{"class":205},"(n ",[199,920,921],{"class":231},"-",[199,923,924],{"class":248}," 1",[199,926,220],{"class":205},[199,928,929],{"class":201,"line":446},[199,930,931],{"class":205},"  });\n",[199,933,934],{"class":201,"line":470},[199,935,641],{"class":205},[199,937,938],{"class":201,"line":492},[199,939,404],{"emptyLinePlaceholder":34},[199,941,942,944,946,948,951],{"class":201,"line":497},[199,943,206],{"class":205},[199,945,210],{"class":209},[199,947,213],{"class":205},[199,949,950],{"class":216},"\"sync\"",[199,952,220],{"class":205},[199,954,955,958,960,963],{"class":201,"line":707},[199,956,957],{"class":209},"loopMicrotasks",[199,959,213],{"class":205},[199,961,962],{"class":248},"3",[199,964,220],{"class":205},[199,966,967,969,971,973,975,977,979,981,983,985],{"class":201,"line":712},[199,968,46],{"class":209},[199,970,228],{"class":205},[199,972,232],{"class":231},[199,974,235],{"class":205},[199,976,210],{"class":209},[199,978,213],{"class":205},[199,980,242],{"class":216},[199,982,245],{"class":205},[199,984,249],{"class":248},[199,986,220],{"class":205},[22,988,990,998,1006,1014],{"className":989},[25],[27,991,993,308,995],{"className":992},[30],[32,994],{"disabled":34,"type":35},[44,996,997],{},"sync, microtask 3, microtask 2, microtask 1, timeout",[27,999,1001,308,1003],{"className":1000},[30],[32,1002],{"disabled":34,"type":35},[44,1004,1005],{},"sync, timeout, microtask 3, microtask 2, microtask 1",[27,1007,1009,308,1011],{"className":1008},[30],[32,1010],{"disabled":34,"type":35},[44,1012,1013],{},"sync, microtask 3, timeout, microtask 2, microtask 1",[27,1015,1017,308,1019],{"className":1016},[30],[32,1018],{"disabled":34,"type":35},[44,1020,1021],{},"timeout, sync, microtask 3, microtask 2, microtask 1",[64,1023,1024,1026,1033],{},[67,1025,69],{},[71,1027,1028,1030,1031],{},[74,1029,76],{}," A — ",[44,1032,997],{},[71,1034,1035,308,1037,1040,1041,1044,1045,1047],{},[74,1036,82],{},[74,1038,1039],{},"Performance:"," each queued microtask here schedules ",[578,1042,1043],{},"another"," microtask before returning, and the spec says the event loop keeps processing the microtask queue until it is completely empty — including microtasks added while draining — before it's allowed to move to the next macrotask. So all three self-chaining microtasks run back-to-back, and only then does the ",[44,1046,369],{}," macrotask get a turn. This is the mechanism behind a real production hazard: a runaway chain of self-queuing microtasks (or promises) can starve macrotasks — including timers and even browser rendering — indefinitely, since the loop never \"gets around\" to them while microtasks keep refilling the queue.",[14,1049,1050,1054,1152,1179],{"language":182},[17,1051,1053],{"id":1052},"q7-setting-aside-whether-it-works-what-is-the-primary-maintainability-problem-with-this-pattern","Q7. Setting aside whether it works, what is the primary maintainability problem with this pattern?",[188,1055,1056],{"language":182},[191,1057,1059],{"className":193,"code":1058,"language":182,"meta":195,"style":195},"getUser(id, (err, user) => {\n  getPosts(user.id, (err, posts) => {\n    getComments(posts[0].id, (err, comments) => {\n      render(user, posts, comments);\n    });\n  });\n});\n",[44,1060,1061,1083,1104,1130,1138,1143,1147],{"__ignoreMap":195},[199,1062,1063,1066,1069,1072,1074,1077,1079,1081],{"class":201,"line":202},[199,1064,1065],{"class":209},"getUser",[199,1067,1068],{"class":205},"(id, (",[199,1070,1071],{"class":856},"err",[199,1073,173],{"class":205},[199,1075,1076],{"class":856},"user",[199,1078,877],{"class":205},[199,1080,232],{"class":231},[199,1082,895],{"class":205},[199,1084,1085,1088,1091,1093,1095,1098,1100,1102],{"class":201,"line":223},[199,1086,1087],{"class":209},"  getPosts",[199,1089,1090],{"class":205},"(user.id, (",[199,1092,1071],{"class":856},[199,1094,173],{"class":205},[199,1096,1097],{"class":856},"posts",[199,1099,877],{"class":205},[199,1101,232],{"class":231},[199,1103,895],{"class":205},[199,1105,1106,1109,1112,1114,1117,1119,1121,1124,1126,1128],{"class":201,"line":254},[199,1107,1108],{"class":209},"    getComments",[199,1110,1111],{"class":205},"(posts[",[199,1113,249],{"class":248},[199,1115,1116],{"class":205},"].id, (",[199,1118,1071],{"class":856},[199,1120,173],{"class":205},[199,1122,1123],{"class":856},"comments",[199,1125,877],{"class":205},[199,1127,232],{"class":231},[199,1129,895],{"class":205},[199,1131,1132,1135],{"class":201,"line":288},[199,1133,1134],{"class":209},"      render",[199,1136,1137],{"class":205},"(user, posts, comments);\n",[199,1139,1140],{"class":201,"line":434},[199,1141,1142],{"class":205},"    });\n",[199,1144,1145],{"class":201,"line":446},[199,1146,931],{"class":205},[199,1148,1149],{"class":201,"line":470},[199,1150,1151],{"class":205},"});\n",[22,1153,1155,1161,1167,1173],{"className":1154},[25],[27,1156,1158,1160],{"className":1157},[30],[32,1159],{"disabled":34,"type":35}," It runs slower than equivalent synchronous code",[27,1162,1164,1166],{"className":1163},[30],[32,1165],{"disabled":34,"type":35}," JavaScript enforces a maximum callback nesting depth of 3",[27,1168,1170,1172],{"className":1169},[30],[32,1171],{"disabled":34,"type":35}," Nested callbacks cannot access variables from outer scopes",[27,1174,1176,1178],{"className":1175},[30],[32,1177],{"disabled":34,"type":35}," Each nested callback adds indentation and couples unrelated steps into one deeply nested closure, making the code hard to read, test, or modify in isolation — the classic \"pyramid of doom\"",[64,1180,1181,1183,1188],{},[67,1182,69],{},[71,1184,1185,1187],{},[74,1186,76],{}," D — Each nested callback adds indentation and couples unrelated steps into one deeply nested closure, making the code hard to read, test, or modify in isolation — the classic \"pyramid of doom\"",[71,1189,1190,1192,1193,1196,1197,1199,1200,1202],{},[74,1191,82],{}," This is a structural readability problem, not a functional or performance one: every step is defined inline inside the previous step's callback, so the logic marches rightward and none of the steps can be tested, named, or reused independently. Option B invents a nonexistent engine limit — nesting can go arbitrarily deep (until you run out of patience or screen width). Option C is backwards — nested callbacks ",[578,1194,1195],{},"can"," close over outer-scope variables (that's exactly how ",[44,1198,1076],{}," and ",[44,1201,1097],{}," stay accessible inward), which is what makes this pattern work at all, just not cleanly. Option A is unrelated; this code's async cost is the same regardless of nesting style.",[14,1204,1205,1209,1352,1379],{"language":182},[17,1206,1208],{"id":1207},"q8-compared-to-the-deeply-nested-version-in-q7-what-does-refactoring-into-named-top-level-functions-actually-fix","Q8. Compared to the deeply nested version in Q7, what does refactoring into named top-level functions actually fix?",[188,1210,1211],{"language":182},[191,1212,1214],{"className":193,"code":1213,"language":182,"meta":195,"style":195},"function onComments(err, comments) {\n  if (err) return handleError(err);\n  render(comments);\n}\nfunction onPosts(err, posts) {\n  if (err) return handleError(err);\n  getComments(posts[0].id, onComments);\n}\nfunction onUser(err, user) {\n  if (err) return handleError(err);\n  getPosts(user.id, onPosts);\n}\ngetUser(id, onUser);\n",[44,1215,1216,1233,1248,1256,1260,1277,1289,1301,1305,1322,1334,1341,1345],{"__ignoreMap":195},[199,1217,1218,1220,1223,1225,1227,1229,1231],{"class":201,"line":202},[199,1219,616],{"class":231},[199,1221,1222],{"class":209}," onComments",[199,1224,213],{"class":205},[199,1226,1071],{"class":856},[199,1228,173],{"class":205},[199,1230,1123],{"class":856},[199,1232,860],{"class":205},[199,1234,1235,1237,1240,1242,1245],{"class":201,"line":223},[199,1236,865],{"class":231},[199,1238,1239],{"class":205}," (err) ",[199,1241,880],{"class":231},[199,1243,1244],{"class":209}," handleError",[199,1246,1247],{"class":205},"(err);\n",[199,1249,1250,1253],{"class":201,"line":254},[199,1251,1252],{"class":209},"  render",[199,1254,1255],{"class":205},"(comments);\n",[199,1257,1258],{"class":201,"line":288},[199,1259,641],{"class":205},[199,1261,1262,1264,1267,1269,1271,1273,1275],{"class":201,"line":434},[199,1263,616],{"class":231},[199,1265,1266],{"class":209}," onPosts",[199,1268,213],{"class":205},[199,1270,1071],{"class":856},[199,1272,173],{"class":205},[199,1274,1097],{"class":856},[199,1276,860],{"class":205},[199,1278,1279,1281,1283,1285,1287],{"class":201,"line":446},[199,1280,865],{"class":231},[199,1282,1239],{"class":205},[199,1284,880],{"class":231},[199,1286,1244],{"class":209},[199,1288,1247],{"class":205},[199,1290,1291,1294,1296,1298],{"class":201,"line":470},[199,1292,1293],{"class":209},"  getComments",[199,1295,1111],{"class":205},[199,1297,249],{"class":248},[199,1299,1300],{"class":205},"].id, onComments);\n",[199,1302,1303],{"class":201,"line":492},[199,1304,641],{"class":205},[199,1306,1307,1309,1312,1314,1316,1318,1320],{"class":201,"line":497},[199,1308,616],{"class":231},[199,1310,1311],{"class":209}," onUser",[199,1313,213],{"class":205},[199,1315,1071],{"class":856},[199,1317,173],{"class":205},[199,1319,1076],{"class":856},[199,1321,860],{"class":205},[199,1323,1324,1326,1328,1330,1332],{"class":201,"line":707},[199,1325,865],{"class":231},[199,1327,1239],{"class":205},[199,1329,880],{"class":231},[199,1331,1244],{"class":209},[199,1333,1247],{"class":205},[199,1335,1336,1338],{"class":201,"line":712},[199,1337,1087],{"class":209},[199,1339,1340],{"class":205},"(user.id, onPosts);\n",[199,1342,1343],{"class":201,"line":721},[199,1344,641],{"class":205},[199,1346,1347,1349],{"class":201,"line":728},[199,1348,1065],{"class":209},[199,1350,1351],{"class":205},"(id, onUser);\n",[22,1353,1355,1361,1367,1373],{"className":1354},[25],[27,1356,1358,1360],{"className":1357},[30],[32,1359],{"disabled":34,"type":35}," It makes the code run synchronously instead of asynchronously",[27,1362,1364,1366],{"className":1363},[30],[32,1365],{"disabled":34,"type":35}," It flattens the visual nesting, gives each step a name, and lets each step be tested independently — but the underlying callback-based control flow (and its complexity) is otherwise unchanged",[27,1368,1370,1372],{"className":1369},[30],[32,1371],{"disabled":34,"type":35}," It converts the callbacks into Promises automatically",[27,1374,1376,1378],{"className":1375},[30],[32,1377],{"disabled":34,"type":35}," It eliminates the need for error handling entirely",[64,1380,1381,1383,1388],{},[67,1382,69],{},[71,1384,1385,1387],{},[74,1386,76],{}," B — It flattens the visual nesting, gives each step a name, and lets each step be tested independently — but the underlying callback-based control flow (and its complexity) is otherwise unchanged",[71,1389,1390,308,1392,1395,1396,1398,1399,1401],{},[74,1391,82],{},[74,1393,1394],{},"Idiom:"," naming each step as a top-level function is a genuine readability win over Q7's pyramid — each function can be reasoned about, unit-tested, and reused on its own — but it's a purely structural fix. Execution order, the error-first convention (checking ",[44,1397,1071],{}," at every single step, as this snippet still does), and the overall async wiring are identical to the nested version. Option D is contradicted by the code itself, which explicitly checks ",[44,1400,1071],{}," at every level. Option C is false — nothing here touches Promises; that's a separate refactor covered in the next quiz. Option A is false — none of this changes sync\u002Fasync timing.",[14,1403,1404,1412,1450],{},[17,1405,1407,1408,1411],{"id":1406},"q9-in-nodejs-style-apis-like-fsreadfilepath-err-data-what-does-the-error-first-callback-convention-actually-mean","Q9. In Node.js-style APIs like ",[44,1409,1410],{},"fs.readFile(path, (err, data) => {...})",", what does the \"error-first callback\" convention actually mean?",[22,1413,1415,1432,1438,1444],{"className":1414},[25],[27,1416,1418,1420,1421,1424,1425,159,1428,1431],{"className":1417},[30],[32,1419],{"disabled":34,"type":35}," The callback's first parameter is reserved for an ",[44,1422,1423],{},"Error"," object (or ",[44,1426,1427],{},"null",[44,1429,1430],{},"undefined"," on success), and callers must check it before trusting later parameters — this is a community convention, not something the language enforces",[27,1433,1435,1437],{"className":1434},[30],[32,1436],{"disabled":34,"type":35}," The callback function must be declared before any other code in the file",[27,1439,1441,1443],{"className":1440},[30],[32,1442],{"disabled":34,"type":35}," Errors are automatically thrown first, before the callback ever runs",[27,1445,1447,1449],{"className":1446},[30],[32,1448],{"disabled":34,"type":35}," The first argument is always a plain string describing the error message",[64,1451,1452,1454,1465],{},[67,1453,69],{},[71,1455,1456,1458,1459,1424,1461,159,1463,1431],{},[74,1457,76],{}," A — The callback's first parameter is reserved for an ",[44,1460,1423],{},[44,1462,1427],{},[44,1464,1430],{},[71,1466,1467,308,1469,1471,1472,1475,1476,1478,1479,1481,1482,1485,1486,1488,1489,1491,1492,1494,1495,1498],{},[74,1468,82],{},[74,1470,1394],{}," popularized by early Node.js core APIs, ",[44,1473,1474],{},"callback(err, result)"," puts the error (or ",[44,1477,1427],{}," when there isn't one) in a fixed, predictable position. JavaScript itself does nothing to enforce this — a careless caller who forgets to check ",[44,1480,1071],{}," first will happily read ",[44,1483,1484],{},"result"," even when it's ",[44,1487,1430],{}," or garbage, which is a frequent real-world bug source. Option D is wrong because ",[44,1490,1071],{}," is conventionally an ",[44,1493,1423],{}," instance (with a ",[44,1496,1497],{},".message"," property), not a bare string. Options B and C describe behavior nothing in the convention or the language actually provides.",[14,1500,1501,1505,1598,1640],{"language":182},[17,1502,1504],{"id":1503},"q10-what-happens-when-this-code-runs","Q10. What happens when this code runs?",[188,1506,1507],{"language":182},[191,1508,1510],{"className":193,"code":1509,"language":182,"meta":195,"style":195},"try {\n  setTimeout(() => {\n    throw new Error(\"boom\");\n  }, 0);\n} catch (e) {\n  console.log(\"caught:\", e.message);\n}\nconsole.log(\"after try\u002Fcatch\");\n",[44,1511,1512,1519,1529,1547,1556,1567,1581,1585],{"__ignoreMap":195},[199,1513,1514,1517],{"class":201,"line":202},[199,1515,1516],{"class":231},"try",[199,1518,895],{"class":205},[199,1520,1521,1523,1525,1527],{"class":201,"line":223},[199,1522,655],{"class":209},[199,1524,228],{"class":205},[199,1526,232],{"class":231},[199,1528,895],{"class":205},[199,1530,1531,1534,1537,1540,1542,1545],{"class":201,"line":254},[199,1532,1533],{"class":231},"    throw",[199,1535,1536],{"class":231}," new",[199,1538,1539],{"class":209}," Error",[199,1541,213],{"class":205},[199,1543,1544],{"class":216},"\"boom\"",[199,1546,220],{"class":205},[199,1548,1549,1552,1554],{"class":201,"line":288},[199,1550,1551],{"class":205},"  }, ",[199,1553,249],{"class":248},[199,1555,220],{"class":205},[199,1557,1558,1561,1564],{"class":201,"line":434},[199,1559,1560],{"class":205},"} ",[199,1562,1563],{"class":231},"catch",[199,1565,1566],{"class":205}," (e) {\n",[199,1568,1569,1571,1573,1575,1578],{"class":201,"line":446},[199,1570,627],{"class":205},[199,1572,210],{"class":209},[199,1574,213],{"class":205},[199,1576,1577],{"class":216},"\"caught:\"",[199,1579,1580],{"class":205},", e.message);\n",[199,1582,1583],{"class":201,"line":470},[199,1584,641],{"class":205},[199,1586,1587,1589,1591,1593,1596],{"class":201,"line":492},[199,1588,206],{"class":205},[199,1590,210],{"class":209},[199,1592,213],{"class":205},[199,1594,1595],{"class":216},"\"after try\u002Fcatch\"",[199,1597,220],{"class":205},[22,1599,1601,1614,1620,1629],{"className":1600},[25],[27,1602,1604,1606,1607,1610,1611],{"className":1603},[30],[32,1605],{"disabled":34,"type":35}," Logs ",[44,1608,1609],{},"caught: boom"," then ",[44,1612,1613],{},"after try\u002Fcatch",[27,1615,1617,1619],{"className":1616},[30],[32,1618],{"disabled":34,"type":35}," Nothing logs at all; the error is silently swallowed",[27,1621,1623,1625,1626,1628],{"className":1622},[30],[32,1624],{"disabled":34,"type":35}," The program crashes immediately at the ",[44,1627,46],{}," line, before anything logs",[27,1630,1632,1606,1634,1636,1637,1639],{"className":1631},[30],[32,1633],{"disabled":34,"type":35},[44,1635,1613],{},", and then the thrown error surfaces as an unhandled exception, because the callback runs in a separate macrotask turn, on a stack that no longer has the original ",[44,1638,1516],{}," block active",[64,1641,1642,1644,1653],{},[67,1643,69],{},[71,1645,1646,1648,1649,1636,1651,1639],{},[74,1647,76],{}," D — Logs ",[44,1650,1613],{},[44,1652,1516],{},[71,1654,1655,308,1657,308,1659,1662,1663,1665,1666,1668,1669,1672,1673,308,1675,1678,1679,1681,1682,1684],{},[74,1656,82],{},[74,1658,561],{},[44,1660,1661],{},"try\u002Fcatch"," only guards the code actively on the call stack while it's executing. By the time the ",[44,1664,46],{}," callback finally runs — a fresh call stack, in a later macrotask — the original ",[44,1667,1516],{}," frame is long gone, so the ",[44,1670,1671],{},"throw"," propagates as an uncaught exception (visible as an unhandled error in the console, or a crash in Node without a global handler) rather than being caught. This is one of the most common async beginner traps. The fix is to put ",[44,1674,1661],{},[578,1676,1677],{},"inside"," the callback itself, or to prefer error-first callbacks \u002F promise rejections over ",[44,1680,1671],{}," in async code. Option A is the tempting-but-wrong assumption that a surrounding ",[44,1683,1661],{}," reaches into deferred callbacks.",[14,1686,1687,1691,1809,1844],{"language":182},[17,1688,1690],{"id":1689},"q11-in-nodejs-what-does-this-code-log-and-in-what-order","Q11. In Node.js, what does this code log, and in what order?",[188,1692,1693],{"language":182},[191,1694,1696],{"className":193,"code":1695,"language":182,"meta":195,"style":195},"console.log(\"start\");\n\nsetTimeout(() => console.log(\"timeout\"), 0);\n\nPromise.resolve().then(() => console.log(\"promise\"));\n\nprocess.nextTick(() => console.log(\"nextTick\"));\n\nconsole.log(\"end\");\n",[44,1697,1698,1710,1714,1736,1740,1766,1770,1793,1797],{"__ignoreMap":195},[199,1699,1700,1702,1704,1706,1708],{"class":201,"line":202},[199,1701,206],{"class":205},[199,1703,210],{"class":209},[199,1705,213],{"class":205},[199,1707,217],{"class":216},[199,1709,220],{"class":205},[199,1711,1712],{"class":201,"line":223},[199,1713,404],{"emptyLinePlaceholder":34},[199,1715,1716,1718,1720,1722,1724,1726,1728,1730,1732,1734],{"class":201,"line":254},[199,1717,46],{"class":209},[199,1719,228],{"class":205},[199,1721,232],{"class":231},[199,1723,235],{"class":205},[199,1725,210],{"class":209},[199,1727,213],{"class":205},[199,1729,242],{"class":216},[199,1731,245],{"class":205},[199,1733,249],{"class":248},[199,1735,220],{"class":205},[199,1737,1738],{"class":201,"line":288},[199,1739,404],{"emptyLinePlaceholder":34},[199,1741,1742,1744,1746,1748,1750,1752,1754,1756,1758,1760,1762,1764],{"class":201,"line":434},[199,1743,257],{"class":248},[199,1745,260],{"class":205},[199,1747,263],{"class":209},[199,1749,266],{"class":205},[199,1751,269],{"class":209},[199,1753,228],{"class":205},[199,1755,232],{"class":231},[199,1757,235],{"class":205},[199,1759,210],{"class":209},[199,1761,213],{"class":205},[199,1763,282],{"class":216},[199,1765,285],{"class":205},[199,1767,1768],{"class":201,"line":446},[199,1769,404],{"emptyLinePlaceholder":34},[199,1771,1772,1775,1778,1780,1782,1784,1786,1788,1791],{"class":201,"line":470},[199,1773,1774],{"class":205},"process.",[199,1776,1777],{"class":209},"nextTick",[199,1779,228],{"class":205},[199,1781,232],{"class":231},[199,1783,235],{"class":205},[199,1785,210],{"class":209},[199,1787,213],{"class":205},[199,1789,1790],{"class":216},"\"nextTick\"",[199,1792,285],{"class":205},[199,1794,1795],{"class":201,"line":492},[199,1796,404],{"emptyLinePlaceholder":34},[199,1798,1799,1801,1803,1805,1807],{"class":201,"line":497},[199,1800,206],{"class":205},[199,1802,210],{"class":209},[199,1804,213],{"class":205},[199,1806,297],{"class":216},[199,1808,220],{"class":205},[22,1810,1812,1820,1828,1836],{"className":1811},[25],[27,1813,1815,308,1817],{"className":1814},[30],[32,1816],{"disabled":34,"type":35},[44,1818,1819],{},"start, end, promise, nextTick, timeout",[27,1821,1823,308,1825],{"className":1822},[30],[32,1824],{"disabled":34,"type":35},[44,1826,1827],{},"start, nextTick, end, promise, timeout",[27,1829,1831,308,1833],{"className":1830},[30],[32,1832],{"disabled":34,"type":35},[44,1834,1835],{},"start, end, nextTick, promise, timeout",[27,1837,1839,308,1841],{"className":1838},[30],[32,1840],{"disabled":34,"type":35},[44,1842,1843],{},"start, end, timeout, nextTick, promise",[64,1845,1846,1848,1854],{},[67,1847,69],{},[71,1849,1850,778,1852],{},[74,1851,76],{},[44,1853,1835],{},[71,1855,1856,308,1858,1861,1862,173,1864,1866,1867,1870,1871,1873,1874,1876,1877,1879,1880,1882,1883,1885,1886,1888,1889,1891],{},[74,1857,82],{},[74,1859,1860],{},"Portability:"," synchronous code always runs first (",[44,1863,354],{},[44,1865,358],{},"). Node.js gives ",[44,1868,1869],{},"process.nextTick"," callbacks an even higher priority than the standard microtask (promise) queue — Node fully drains the ",[44,1872,1777],{}," queue before it drains promise microtasks, at the end of every phase. So ",[44,1875,1777],{}," logs before ",[44,1878,365],{},", and only after both queues are empty does the ",[44,1881,369],{}," macrotask run. This is explicitly a Node-specific, non-standard behavior — there is no ",[44,1884,1869],{}," in browsers, and code that needs a portable \"run this as soon as possible, before other microtasks\" primitive should generally reach for ",[44,1887,169],{}," instead, which behaves consistently across environments (though still after ",[44,1890,1777],{}," in Node).",[14,1893,1894,1902,2015,2051],{"language":182},[17,1895,1897,1898,1901],{"id":1896},"q12-given-that-the-busy-wait-loop-below-takes-roughly-3-full-seconds-to-finish-when-does-timeout-fired-actually-log-relative-to-the-requested-100ms-delay","Q12. Given that the busy-wait loop below takes roughly 3 full seconds to finish, when does ",[44,1899,1900],{},"\"timeout fired\""," actually log, relative to the requested 100ms delay?",[188,1903,1904],{"language":182},[191,1905,1907],{"className":193,"code":1906,"language":182,"meta":195,"style":195},"console.log(\"start\");\nsetTimeout(() => console.log(\"timeout fired\"), 100);\n\nconst end = Date.now() + 3000;\nwhile (Date.now() \u003C end) {} \u002F\u002F busy-wait for ~3 seconds\n\nconsole.log(\"loop done\");\n",[44,1908,1909,1921,1944,1948,1976,1998,2002],{"__ignoreMap":195},[199,1910,1911,1913,1915,1917,1919],{"class":201,"line":202},[199,1912,206],{"class":205},[199,1914,210],{"class":209},[199,1916,213],{"class":205},[199,1918,217],{"class":216},[199,1920,220],{"class":205},[199,1922,1923,1925,1927,1929,1931,1933,1935,1937,1939,1942],{"class":201,"line":223},[199,1924,46],{"class":209},[199,1926,228],{"class":205},[199,1928,232],{"class":231},[199,1930,235],{"class":205},[199,1932,210],{"class":209},[199,1934,213],{"class":205},[199,1936,1900],{"class":216},[199,1938,245],{"class":205},[199,1940,1941],{"class":248},"100",[199,1943,220],{"class":205},[199,1945,1946],{"class":201,"line":254},[199,1947,404],{"emptyLinePlaceholder":34},[199,1949,1950,1953,1956,1959,1962,1965,1968,1971,1974],{"class":201,"line":288},[199,1951,1952],{"class":231},"const",[199,1954,1955],{"class":248}," end",[199,1957,1958],{"class":231}," =",[199,1960,1961],{"class":205}," Date.",[199,1963,1964],{"class":209},"now",[199,1966,1967],{"class":205},"() ",[199,1969,1970],{"class":231},"+",[199,1972,1973],{"class":248}," 3000",[199,1975,883],{"class":205},[199,1977,1978,1981,1984,1986,1988,1991,1994],{"class":201,"line":434},[199,1979,1980],{"class":231},"while",[199,1982,1983],{"class":205}," (Date.",[199,1985,1964],{"class":209},[199,1987,1967],{"class":205},[199,1989,1990],{"class":231},"\u003C",[199,1992,1993],{"class":205}," end) {} ",[199,1995,1997],{"class":1996},"sdCPZ","\u002F\u002F busy-wait for ~3 seconds\n",[199,1999,2000],{"class":201,"line":446},[199,2001,404],{"emptyLinePlaceholder":34},[199,2003,2004,2006,2008,2010,2013],{"class":201,"line":470},[199,2005,206],{"class":205},[199,2007,210],{"class":209},[199,2009,213],{"class":205},[199,2011,2012],{"class":216},"\"loop done\"",[199,2014,220],{"class":205},[22,2016,2018,2027,2036,2045],{"className":2017},[25],[27,2019,2021,2023,2024,2026],{"className":2020},[30],[32,2022],{"disabled":34,"type":35}," Exactly 100ms after ",[44,2025,354],{},", on a separate thread, unaffected by the loop",[27,2028,2030,2032,2033,2035],{"className":2029},[30],[32,2031],{"disabled":34,"type":35}," Only after the ~3-second loop finishes and ",[44,2034,2012],{}," logs — the timer became \"due\" around 100ms in, but its callback can't run until the call stack is empty",[27,2037,2039,2041,2042,2044],{"className":2038},[30],[32,2040],{"disabled":34,"type":35}," Immediately after ",[44,2043,354],{},", before the loop even begins",[27,2046,2048,2050],{"className":2047},[30],[32,2049],{"disabled":34,"type":35}," Never — the busy-wait permanently cancels any pending timers",[64,2052,2053,2055,2062],{},[67,2054,69],{},[71,2056,2057,2059,2060,2035],{},[74,2058,76],{}," B — Only after the ~3-second loop finishes and ",[44,2061,2012],{},[71,2063,2064,308,2066,2068,2069,2072,2073,2076,2077,2079,2080,2083],{},[74,2065,82],{},[74,2067,1039],{}," the ",[44,2070,2071],{},"100ms"," delay only controls when the callback becomes ",[578,2074,2075],{},"eligible"," to move from the macrotask queue onto the call stack — it says nothing about the stack actually being free at that moment. Since JS is single-threaded (Q1), the synchronous ",[44,2078,1980],{}," loop occupies the only stack there is for the full 3 seconds, so even though the timer is \"ready\" after 100ms, the event loop has nowhere to run it until the loop finally releases the stack. This is the sharpest version of \"delay is a minimum, not a guarantee\": a blocked stack delays every queued callback, including timers that expired long ago. Option A invents a separate thread for the callback itself, which doesn't exist — only the ",[578,2081,2082],{},"waiting"," happens off-thread, not the callback execution.",[14,2085,2086,2094,2197,2237],{"language":182},[17,2087,2089,2090,2093],{"id":2088},"q13-what-is-the-concrete-risk-in-how-loaddata-is-written-here-given-that-a-callbacks-contract-should-specify-how-many-times-it-can-be-invoked","Q13. What is the concrete risk in how ",[44,2091,2092],{},"loadData"," is written here, given that a callback's contract should specify how many times it can be invoked?",[188,2095,2096],{"language":182},[191,2097,2099],{"className":193,"code":2098,"language":182,"meta":195,"style":195},"function loadData(callback) {\n  fetchFromCache((err, cached) => {\n    if (cached) callback(null, cached);\n  });\n  fetchFromNetwork((err, fresh) => {\n    callback(null, fresh);\n  });\n}\n",[44,2100,2101,2115,2136,2153,2157,2177,2189,2193],{"__ignoreMap":195},[199,2102,2103,2105,2108,2110,2113],{"class":201,"line":202},[199,2104,616],{"class":231},[199,2106,2107],{"class":209}," loadData",[199,2109,213],{"class":205},[199,2111,2112],{"class":856},"callback",[199,2114,860],{"class":205},[199,2116,2117,2120,2123,2125,2127,2130,2132,2134],{"class":201,"line":223},[199,2118,2119],{"class":209},"  fetchFromCache",[199,2121,2122],{"class":205},"((",[199,2124,1071],{"class":856},[199,2126,173],{"class":205},[199,2128,2129],{"class":856},"cached",[199,2131,877],{"class":205},[199,2133,232],{"class":231},[199,2135,895],{"class":205},[199,2137,2138,2141,2144,2146,2148,2150],{"class":201,"line":254},[199,2139,2140],{"class":231},"    if",[199,2142,2143],{"class":205}," (cached) ",[199,2145,2112],{"class":209},[199,2147,213],{"class":205},[199,2149,1427],{"class":248},[199,2151,2152],{"class":205},", cached);\n",[199,2154,2155],{"class":201,"line":288},[199,2156,931],{"class":205},[199,2158,2159,2162,2164,2166,2168,2171,2173,2175],{"class":201,"line":434},[199,2160,2161],{"class":209},"  fetchFromNetwork",[199,2163,2122],{"class":205},[199,2165,1071],{"class":856},[199,2167,173],{"class":205},[199,2169,2170],{"class":856},"fresh",[199,2172,877],{"class":205},[199,2174,232],{"class":231},[199,2176,895],{"class":205},[199,2178,2179,2182,2184,2186],{"class":201,"line":446},[199,2180,2181],{"class":209},"    callback",[199,2183,213],{"class":205},[199,2185,1427],{"class":248},[199,2187,2188],{"class":205},", fresh);\n",[199,2190,2191],{"class":201,"line":470},[199,2192,931],{"class":205},[199,2194,2195],{"class":201,"line":492},[199,2196,641],{"class":205},[22,2198,2200,2209,2218,2231],{"className":2199},[25],[27,2201,2203,2205,2206,2208],{"className":2202},[30],[32,2204],{"disabled":34,"type":35}," If both the cache lookup and the network fetch succeed, ",[44,2207,2112],{}," runs twice — once with cached data, once with fresh data — which can cause consumers to double-render UI, double-submit data, or throw if they assumed single-invocation semantics",[27,2210,2212,2214,2215,2217],{"className":2211},[30],[32,2213],{"disabled":34,"type":35}," It's guaranteed to call ",[44,2216,2112],{}," exactly once, because JavaScript functions can only be invoked once per registration",[27,2219,2221,2223,2224,2227,2228,2230],{"className":2220},[30],[32,2222],{"disabled":34,"type":35}," This code throws a ",[44,2225,2226],{},"SyntaxError",", because ",[44,2229,2112],{}," is referenced in two separate places",[27,2232,2234,2236],{"className":2233},[30],[32,2235],{"disabled":34,"type":35}," Only the network fetch's callback actually runs; the cache branch is unreachable dead code",[64,2238,2239,2241,2248],{},[67,2240,69],{},[71,2242,2243,2245,2246,2208],{},[74,2244,76],{}," A — If both the cache lookup and the network fetch succeed, ",[44,2247,2112],{},[71,2249,2250,308,2252,2254,2255,2257,2258,2260],{},[74,2251,82],{},[74,2253,561],{}," nothing in JavaScript stops a captured function reference from being called any number of times — each independent async operation here holds its own reference to ",[44,2256,2112],{}," and will invoke it on completion regardless of what the other one does. If both succeed, ",[44,2259,2112],{}," fires twice with two different results, which is a genuine, common bug: consumers that assume \"called once\" (a common implicit assumption for callback-based APIs) may double-render, double-submit, or crash on the second call. Fixing it requires an explicit guard (a \"already called\" flag, unregistering after the first call, or restructuring so only one source can win). Option B states an invented guarantee JS does not provide.",[14,2262,2263,2267,2420,2455],{"language":182},[17,2264,2266],{"id":2265},"q14-what-does-this-code-log-and-in-what-order","Q14. What does this code log, and in what order?",[188,2268,2269],{"language":182},[191,2270,2272],{"className":193,"code":2271,"language":182,"meta":195,"style":195},"console.log(1);\n\nsetTimeout(() => console.log(2), 0);\nsetTimeout(() => console.log(3), 0);\n\nPromise.resolve().then(() => {\n  console.log(4);\n  Promise.resolve().then(() => console.log(5));\n});\n\nconsole.log(6);\n",[44,2273,2274,2287,2291,2314,2336,2340,2358,2371,2399,2403,2407],{"__ignoreMap":195},[199,2275,2276,2278,2280,2282,2285],{"class":201,"line":202},[199,2277,206],{"class":205},[199,2279,210],{"class":209},[199,2281,213],{"class":205},[199,2283,2284],{"class":248},"1",[199,2286,220],{"class":205},[199,2288,2289],{"class":201,"line":223},[199,2290,404],{"emptyLinePlaceholder":34},[199,2292,2293,2295,2297,2299,2301,2303,2305,2308,2310,2312],{"class":201,"line":254},[199,2294,46],{"class":209},[199,2296,228],{"class":205},[199,2298,232],{"class":231},[199,2300,235],{"class":205},[199,2302,210],{"class":209},[199,2304,213],{"class":205},[199,2306,2307],{"class":248},"2",[199,2309,245],{"class":205},[199,2311,249],{"class":248},[199,2313,220],{"class":205},[199,2315,2316,2318,2320,2322,2324,2326,2328,2330,2332,2334],{"class":201,"line":288},[199,2317,46],{"class":209},[199,2319,228],{"class":205},[199,2321,232],{"class":231},[199,2323,235],{"class":205},[199,2325,210],{"class":209},[199,2327,213],{"class":205},[199,2329,962],{"class":248},[199,2331,245],{"class":205},[199,2333,249],{"class":248},[199,2335,220],{"class":205},[199,2337,2338],{"class":201,"line":434},[199,2339,404],{"emptyLinePlaceholder":34},[199,2341,2342,2344,2346,2348,2350,2352,2354,2356],{"class":201,"line":446},[199,2343,257],{"class":248},[199,2345,260],{"class":205},[199,2347,263],{"class":209},[199,2349,266],{"class":205},[199,2351,269],{"class":209},[199,2353,228],{"class":205},[199,2355,232],{"class":231},[199,2357,895],{"class":205},[199,2359,2360,2362,2364,2366,2369],{"class":201,"line":470},[199,2361,627],{"class":205},[199,2363,210],{"class":209},[199,2365,213],{"class":205},[199,2367,2368],{"class":248},"4",[199,2370,220],{"class":205},[199,2372,2373,2376,2378,2380,2382,2384,2386,2388,2390,2392,2394,2397],{"class":201,"line":492},[199,2374,2375],{"class":248},"  Promise",[199,2377,260],{"class":205},[199,2379,263],{"class":209},[199,2381,266],{"class":205},[199,2383,269],{"class":209},[199,2385,228],{"class":205},[199,2387,232],{"class":231},[199,2389,235],{"class":205},[199,2391,210],{"class":209},[199,2393,213],{"class":205},[199,2395,2396],{"class":248},"5",[199,2398,285],{"class":205},[199,2400,2401],{"class":201,"line":497},[199,2402,1151],{"class":205},[199,2404,2405],{"class":201,"line":707},[199,2406,404],{"emptyLinePlaceholder":34},[199,2408,2409,2411,2413,2415,2418],{"class":201,"line":712},[199,2410,206],{"class":205},[199,2412,210],{"class":209},[199,2414,213],{"class":205},[199,2416,2417],{"class":248},"6",[199,2419,220],{"class":205},[22,2421,2423,2431,2439,2447],{"className":2422},[25],[27,2424,2426,308,2428],{"className":2425},[30],[32,2427],{"disabled":34,"type":35},[44,2429,2430],{},"1, 6, 4, 2, 5, 3",[27,2432,2434,308,2436],{"className":2433},[30],[32,2435],{"disabled":34,"type":35},[44,2437,2438],{},"1, 4, 5, 6, 2, 3",[27,2440,2442,308,2444],{"className":2441},[30],[32,2443],{"disabled":34,"type":35},[44,2445,2446],{},"1, 6, 2, 3, 4, 5",[27,2448,2450,308,2452],{"className":2449},[30],[32,2451],{"disabled":34,"type":35},[44,2453,2454],{},"1, 6, 4, 5, 2, 3",[64,2456,2457,2459,2465],{},[67,2458,69],{},[71,2460,2461,344,2463],{},[74,2462,76],{},[44,2464,2454],{},[71,2466,2467,2469,2470,173,2472,2474,2475,2477,2478,2480,2481,2483,2484,2487,2488,2490,2491,355,2493,2495,2496,1199,2498,2500],{},[74,2468,82],{}," Synchronous code runs first: ",[44,2471,2284],{},[44,2473,2417],{},". The microtask queue then runs: the first ",[44,2476,158],{}," logs ",[44,2479,2368],{}," and, while executing, schedules a nested ",[44,2482,158],{}," — which joins the ",[578,2485,2486],{},"same"," still-draining microtask queue and therefore still runs before any macrotask, logging ",[44,2489,2396],{},". Only once the microtask queue is completely empty does the event loop move to the two queued timeouts, running them in the order they were queued (",[44,2492,2307],{},[44,2494,962],{},", since equal 0ms delays preserve FIFO order). Option A wrongly slots a macrotask between ",[44,2497,2368],{},[44,2499,2396],{},". Option C wrongly runs both macrotasks before any microtask.",[14,2502,2503,2507,2596,2630],{"language":182},[17,2504,2506],{"id":2505},"q15-what-does-this-code-log-and-in-what-order","Q15. What does this code log, and in what order?",[188,2508,2509],{"language":182},[191,2510,2512],{"className":193,"code":2511,"language":182,"meta":195,"style":195},"console.log(\"A\");\nqueueMicrotask(() => console.log(\"B\"));\nsetTimeout(() => console.log(\"C\"), 0);\nqueueMicrotask(() => console.log(\"D\"));\nconsole.log(\"E\");\n",[44,2513,2514,2526,2544,2566,2584],{"__ignoreMap":195},[199,2515,2516,2518,2520,2522,2524],{"class":201,"line":202},[199,2517,206],{"class":205},[199,2519,210],{"class":209},[199,2521,213],{"class":205},[199,2523,397],{"class":216},[199,2525,220],{"class":205},[199,2527,2528,2530,2532,2534,2536,2538,2540,2542],{"class":201,"line":223},[199,2529,169],{"class":209},[199,2531,228],{"class":205},[199,2533,232],{"class":231},[199,2535,235],{"class":205},[199,2537,210],{"class":209},[199,2539,213],{"class":205},[199,2541,421],{"class":216},[199,2543,285],{"class":205},[199,2545,2546,2548,2550,2552,2554,2556,2558,2560,2562,2564],{"class":201,"line":254},[199,2547,46],{"class":209},[199,2549,228],{"class":205},[199,2551,232],{"class":231},[199,2553,235],{"class":205},[199,2555,210],{"class":209},[199,2557,213],{"class":205},[199,2559,464],{"class":216},[199,2561,245],{"class":205},[199,2563,249],{"class":248},[199,2565,220],{"class":205},[199,2567,2568,2570,2572,2574,2576,2578,2580,2582],{"class":201,"line":288},[199,2569,169],{"class":209},[199,2571,228],{"class":205},[199,2573,232],{"class":231},[199,2575,235],{"class":205},[199,2577,210],{"class":209},[199,2579,213],{"class":205},[199,2581,487],{"class":216},[199,2583,285],{"class":205},[199,2585,2586,2588,2590,2592,2594],{"class":201,"line":434},[199,2587,206],{"class":205},[199,2589,210],{"class":209},[199,2591,213],{"class":205},[199,2593,506],{"class":216},[199,2595,220],{"class":205},[22,2597,2599,2607,2615,2623],{"className":2598},[25],[27,2600,2602,308,2604],{"className":2601},[30],[32,2603],{"disabled":34,"type":35},[44,2605,2606],{},"A, B, D, E, C",[27,2608,2610,308,2612],{"className":2609},[30],[32,2611],{"disabled":34,"type":35},[44,2613,2614],{},"A, B, E, D, C",[27,2616,2618,308,2620],{"className":2617},[30],[32,2619],{"disabled":34,"type":35},[44,2621,2622],{},"A, E, B, D, C",[27,2624,2626,308,2628],{"className":2625},[30],[32,2627],{"disabled":34,"type":35},[44,2629,543],{},[64,2631,2632,2634,2640],{},[67,2633,69],{},[71,2635,2636,778,2638],{},[74,2637,76],{},[44,2639,2622],{},[71,2641,2642,308,2644,2646,2647,2649,2650,173,2652,2654,2655,173,2657,2659,2660,2662,2663,2665],{},[74,2643,82],{},[44,2645,169],{}," schedules its callback on the exact same priority tier as promise ",[44,2648,158],{}," callbacks — it runs after all synchronous code finishes, in the order the microtasks were queued, and always before the next macrotask. So the synchronous log lines finish first (",[44,2651,565],{},[44,2653,568],{},"), then the two microtasks run in FIFO order (",[44,2656,590],{},[44,2658,586],{},"), and only then does the timeout macrotask fire (",[44,2661,575],{},"). Options A and B both interleave a microtask before synchronous code (",[44,2664,568],{},") has finished, which never happens — synchronous execution always runs to completion first.",[14,2667,2668,2679,2710],{},[17,2669,2671,2672,159,2675,2678],{"id":2670},"q16-for-sequencing-several-dependent-async-steps-fetch-a-user-then-their-posts-then-comments-on-the-first-post-why-do-modern-codebases-generally-avoid-deeply-nested-callbacks-in-favor-of-promise-chains-or-asyncawait","Q16. For sequencing several dependent async steps (fetch a user, then their posts, then comments on the first post), why do modern codebases generally avoid deeply nested callbacks in favor of promise chains (or ",[44,2673,2674],{},"async",[44,2676,2677],{},"await",")?",[22,2680,2682,2692,2698,2704],{"className":2681},[25],[27,2683,2685,2687,2688,2691],{"className":2684},[30],[32,2686],{"disabled":34,"type":35}," Promise-based sequencing flattens the code into a linear chain, and centralizes error handling — a single rejection can propagate through the whole chain — removing the pyramid-of-doom indentation and the per-step ",[44,2689,2690],{},"if (err) return handleError(err)"," boilerplate that manual callbacks require",[27,2693,2695,2697],{"className":2694},[30],[32,2696],{"disabled":34,"type":35}," Callbacks are deprecated and no longer supported in modern JS engines",[27,2699,2701,2703],{"className":2700},[30],[32,2702],{"disabled":34,"type":35}," Promises execute synchronously, bypassing the event loop entirely, which makes them inherently faster",[27,2705,2707,2709],{"className":2706},[30],[32,2708],{"disabled":34,"type":35}," Callbacks cannot access outer-scope variables, so promises are required for closures to work",[64,2711,2712,2714,2721],{},[67,2713,69],{},[71,2715,2716,2718,2719,2691],{},[74,2717,76],{}," A — Promise-based sequencing flattens the code into a linear chain, and centralizes error handling — a single rejection can propagate through the whole chain — removing the pyramid-of-doom indentation and the per-step ",[44,2720,2690],{},[71,2722,2723,308,2725,2727,2728,2730,2731,2734,2735,2737],{},[74,2724,82],{},[74,2726,1394],{}," the win is structural, not about raw speed or capability — promises are, under the hood, still built on callbacks and the microtask queue (Q2), so option C's \"bypasses the event loop\" claim is false. Option D is also false; callbacks close over outer scope perfectly well, which is precisely what made the nested pattern in Q7 possible in the first place. Option B is false — callbacks remain foundational and are not deprecated. The genuine benefit, covered in depth in the next quiz on Promises, is that ",[44,2729,129],{}," chains read top-to-bottom instead of nesting rightward, and a single trailing ",[44,2732,2733],{},".catch()"," can handle rejection from any step in the chain instead of requiring a manual ",[44,2736,1071],{}," check at every level.",[14,2739,2740,2749,2862,2909],{"language":182},[17,2741,2743,2744,1199,2746,2748],{"id":2742},"q17-the-loop-below-takes-roughly-200ms-to-finish-synchronously-given-that-in-what-order-do-a-and-b-log-and-why","Q17. The loop below takes roughly 200ms to finish synchronously. Given that, in what order do ",[44,2745,397],{},[44,2747,421],{}," log, and why?",[188,2750,2751],{"language":182},[191,2752,2754],{"className":193,"code":2753,"language":182,"meta":195,"style":195},"setTimeout(() => console.log(\"A\"), 50);\nsetTimeout(() => console.log(\"B\"), 10);\n\nfor (let i = 0; i \u003C 1_000_000_000; i++) {} \u002F\u002F ~200ms of synchronous work\n\nconsole.log(\"done looping\");\n",[44,2755,2756,2779,2802,2806,2845,2849],{"__ignoreMap":195},[199,2757,2758,2760,2762,2764,2766,2768,2770,2772,2774,2777],{"class":201,"line":202},[199,2759,46],{"class":209},[199,2761,228],{"class":205},[199,2763,232],{"class":231},[199,2765,235],{"class":205},[199,2767,210],{"class":209},[199,2769,213],{"class":205},[199,2771,397],{"class":216},[199,2773,245],{"class":205},[199,2775,2776],{"class":248},"50",[199,2778,220],{"class":205},[199,2780,2781,2783,2785,2787,2789,2791,2793,2795,2797,2800],{"class":201,"line":223},[199,2782,46],{"class":209},[199,2784,228],{"class":205},[199,2786,232],{"class":231},[199,2788,235],{"class":205},[199,2790,210],{"class":209},[199,2792,213],{"class":205},[199,2794,421],{"class":216},[199,2796,245],{"class":205},[199,2798,2799],{"class":248},"10",[199,2801,220],{"class":205},[199,2803,2804],{"class":201,"line":254},[199,2805,404],{"emptyLinePlaceholder":34},[199,2807,2808,2811,2814,2817,2820,2823,2825,2828,2830,2833,2836,2839,2842],{"class":201,"line":288},[199,2809,2810],{"class":231},"for",[199,2812,2813],{"class":205}," (",[199,2815,2816],{"class":231},"let",[199,2818,2819],{"class":205}," i ",[199,2821,2822],{"class":231},"=",[199,2824,874],{"class":248},[199,2826,2827],{"class":205},"; i ",[199,2829,1990],{"class":231},[199,2831,2832],{"class":248}," 1_000_000_000",[199,2834,2835],{"class":205},"; i",[199,2837,2838],{"class":231},"++",[199,2840,2841],{"class":205},") {} ",[199,2843,2844],{"class":1996},"\u002F\u002F ~200ms of synchronous work\n",[199,2846,2847],{"class":201,"line":434},[199,2848,404],{"emptyLinePlaceholder":34},[199,2850,2851,2853,2855,2857,2860],{"class":201,"line":446},[199,2852,206],{"class":205},[199,2854,210],{"class":209},[199,2856,213],{"class":205},[199,2858,2859],{"class":216},"\"done looping\"",[199,2861,220],{"class":205},[22,2863,2865,2875,2887,2893],{"className":2864},[25],[27,2866,2868,308,2870,355,2872,2874],{"className":2867},[30],[32,2869],{"disabled":34,"type":35},[44,2871,565],{},[44,2873,590],{}," — later-registered timers always run first",[27,2876,2878,2880,2881,2883,2884,2886],{"className":2877},[30],[32,2879],{"disabled":34,"type":35}," Only ",[44,2882,565],{}," fires; ",[44,2885,590],{},"'s shorter delay means it gets discarded as \"missed\"",[27,2888,2890,2892],{"className":2889},[30],[32,2891],{"disabled":34,"type":35}," They fire at the exact same moment, since both delays elapsed during the loop",[27,2894,2896,308,2898,355,2900,2902,2903,2905,2906,2908],{"className":2895},[30],[32,2897],{"disabled":34,"type":35},[44,2899,590],{},[44,2901,565],{}," — both delays have long since elapsed by the time the loop finishes, so both callbacks are already queued, in the order their delays expired (",[44,2904,590],{},"'s 10ms elapsed before ",[44,2907,565],{},"'s 50ms)",[64,2910,2911,2913,2925],{},[67,2912,69],{},[71,2914,2915,344,2917,355,2919,2902,2921,2905,2923,2908],{},[74,2916,76],{},[44,2918,590],{},[44,2920,565],{},[44,2922,590],{},[44,2924,565],{},[71,2926,2927,2929,2930,2932,2933,2935],{},[74,2928,82],{}," As established in Q12, a busy synchronous loop blocks the stack for its entire duration regardless of what timers become \"due\" in the meantime. By the time the ~200ms loop finally releases the stack, both the 10ms and 50ms timers are well overdue and sitting in the macrotask queue, ordered by when each became eligible — ",[44,2931,590],{}," (10ms) became due before ",[44,2934,565],{}," (50ms), so it's queued first and runs first. Option A wrongly uses source-order registration as the tiebreaker instead of elapsed-delay order. Option C is impossible — the event loop only ever runs one macrotask at a time. Option B fabricates a \"missed timer\" behavior that doesn't exist; a late timer still fires, just later than requested.",[14,2937,2938,2946,3083,3118],{"language":182},[17,2939,2941,2942,2945],{"id":2940},"q18-what-does-this-code-log-and-specifically-where-does-executor-appear-in-the-output","Q18. What does this code log, and specifically, where does ",[44,2943,2944],{},"\"executor\""," appear in the output?",[188,2947,2948],{"language":182},[191,2949,2951],{"className":193,"code":2950,"language":182,"meta":195,"style":195},"setTimeout(() => console.log(\"timeout 1\"), 0);\n\nnew Promise((resolve) => {\n  console.log(\"executor\");\n  resolve();\n}).then(() => console.log(\"then 1\"));\n\nsetTimeout(() => console.log(\"timeout 2\"), 0);\n\nconsole.log(\"sync end\");\n",[44,2952,2953,2976,2980,2998,3010,3017,3039,3043,3066,3070],{"__ignoreMap":195},[199,2954,2955,2957,2959,2961,2963,2965,2967,2970,2972,2974],{"class":201,"line":202},[199,2956,46],{"class":209},[199,2958,228],{"class":205},[199,2960,232],{"class":231},[199,2962,235],{"class":205},[199,2964,210],{"class":209},[199,2966,213],{"class":205},[199,2968,2969],{"class":216},"\"timeout 1\"",[199,2971,245],{"class":205},[199,2973,249],{"class":248},[199,2975,220],{"class":205},[199,2977,2978],{"class":201,"line":223},[199,2979,404],{"emptyLinePlaceholder":34},[199,2981,2982,2985,2988,2990,2992,2994,2996],{"class":201,"line":254},[199,2983,2984],{"class":231},"new",[199,2986,2987],{"class":248}," Promise",[199,2989,2122],{"class":205},[199,2991,263],{"class":856},[199,2993,877],{"class":205},[199,2995,232],{"class":231},[199,2997,895],{"class":205},[199,2999,3000,3002,3004,3006,3008],{"class":201,"line":288},[199,3001,627],{"class":205},[199,3003,210],{"class":209},[199,3005,213],{"class":205},[199,3007,2944],{"class":216},[199,3009,220],{"class":205},[199,3011,3012,3015],{"class":201,"line":434},[199,3013,3014],{"class":209},"  resolve",[199,3016,718],{"class":205},[199,3018,3019,3022,3024,3026,3028,3030,3032,3034,3037],{"class":201,"line":446},[199,3020,3021],{"class":205},"}).",[199,3023,269],{"class":209},[199,3025,228],{"class":205},[199,3027,232],{"class":231},[199,3029,235],{"class":205},[199,3031,210],{"class":209},[199,3033,213],{"class":205},[199,3035,3036],{"class":216},"\"then 1\"",[199,3038,285],{"class":205},[199,3040,3041],{"class":201,"line":470},[199,3042,404],{"emptyLinePlaceholder":34},[199,3044,3045,3047,3049,3051,3053,3055,3057,3060,3062,3064],{"class":201,"line":492},[199,3046,46],{"class":209},[199,3048,228],{"class":205},[199,3050,232],{"class":231},[199,3052,235],{"class":205},[199,3054,210],{"class":209},[199,3056,213],{"class":205},[199,3058,3059],{"class":216},"\"timeout 2\"",[199,3061,245],{"class":205},[199,3063,249],{"class":248},[199,3065,220],{"class":205},[199,3067,3068],{"class":201,"line":497},[199,3069,404],{"emptyLinePlaceholder":34},[199,3071,3072,3074,3076,3078,3081],{"class":201,"line":707},[199,3073,206],{"class":205},[199,3075,210],{"class":209},[199,3077,213],{"class":205},[199,3079,3080],{"class":216},"\"sync end\"",[199,3082,220],{"class":205},[22,3084,3086,3094,3102,3110],{"className":3085},[25],[27,3087,3089,308,3091],{"className":3088},[30],[32,3090],{"disabled":34,"type":35},[44,3092,3093],{},"sync end, executor, then 1, timeout 1, timeout 2",[27,3095,3097,308,3099],{"className":3096},[30],[32,3098],{"disabled":34,"type":35},[44,3100,3101],{},"executor, sync end, then 1, timeout 1, timeout 2",[27,3103,3105,308,3107],{"className":3104},[30],[32,3106],{"disabled":34,"type":35},[44,3108,3109],{},"executor, then 1, sync end, timeout 1, timeout 2",[27,3111,3113,308,3115],{"className":3112},[30],[32,3114],{"disabled":34,"type":35},[44,3116,3117],{},"timeout 1, timeout 2, executor, sync end, then 1",[64,3119,3120,3122,3128],{},[67,3121,69],{},[71,3123,3124,552,3126],{},[74,3125,76],{},[44,3127,3101],{},[71,3129,3130,308,3132,3134,3135,3138,3139,3142,3143,3145,3146,3148,3149,3151,3152,3154,3155,3158,3159,3161,3162,3164,3165,3168,3169,159,3171,3173],{},[74,3131,82],{},[74,3133,561],{}," the function passed to ",[44,3136,3137],{},"new Promise(...)"," — the \"executor\" — runs ",[74,3140,3141],{},"synchronously and immediately"," the moment the constructor is called; it is not deferred at all. So ",[44,3144,2944],{}," logs right where the ",[44,3147,3137],{}," line sits in the normal synchronous flow, before ",[44,3150,3080],{},". Only the ",[44,3153,129],{}," reaction is deferred, to the microtask queue, running after all synchronous code (",[44,3156,3157],{},"then 1","), and the two ",[44,3160,46],{}," callbacks run last, in registration order. The common misconception (option A) treats everything inside ",[44,3163,3137],{}," as automatically async — it isn't; only the resolution ",[578,3166,3167],{},"handlers"," attached via ",[44,3170,158],{},[44,3172,162],{}," get queued.",[14,3175,3176,3195,3238],{},[17,3177,3179,3180,3183,3184,3187,3188,3191,3192,3194],{"id":3178},"q19-a-codebases-saveuseruser-cb-internally-calls-three-callback-based-apis-in-sequence-each-depending-on-the-previous-result-a-teammate-proposes-wrapping-only-the-outermost-call-to-saveuser-in-a-trycatch-to-handle-errors-from-the-whole-chain-why-is-this-unsound-given-the-error-first-callback-convention-from-q9","Q19. A codebase's ",[44,3181,3182],{},"saveUser(user, cb)"," internally calls three callback-based APIs in sequence, each depending on the previous result. A teammate proposes wrapping only the ",[578,3185,3186],{},"outermost"," call to ",[44,3189,3190],{},"saveUser"," in a ",[44,3193,1661],{}," to handle errors from the whole chain. Why is this unsound, given the error-first callback convention from Q9?",[22,3196,3198,3207,3215,3229],{"className":3197},[25],[27,3199,3201,3203,3204,3206],{"className":3200},[30],[32,3202],{"disabled":34,"type":35}," It's a fine approach — ",[44,3205,1661],{}," works identically across synchronous and asynchronous code in JavaScript",[27,3208,3210,308,3212,3214],{"className":3209},[30],[32,3211],{"disabled":34,"type":35},[44,3213,1661],{}," is unnecessary here, because callback-based code never fails",[27,3216,3218,3220,3221,3223,3224,3226,3227],{"className":3217},[30],[32,3219],{"disabled":34,"type":35}," Errors from callback-based async APIs are delivered (by convention) as the ",[44,3222,1071],{}," argument to each individual callback, not thrown onto the call stack that made the initiating call — a surrounding ",[44,3225,1661],{}," cannot intercept them, so each nested callback must check its own ",[44,3228,1071],{},[27,3230,3232,3234,3235,3237],{"className":3231},[30],[32,3233],{"disabled":34,"type":35}," The outer ",[44,3236,1661],{}," will catch errors from the first callback only, not the second or third",[64,3239,3240,3242,3253],{},[67,3241,69],{},[71,3243,3244,3246,3247,3223,3249,3226,3251],{},[74,3245,76],{}," C — Errors from callback-based async APIs are delivered (by convention) as the ",[44,3248,1071],{},[44,3250,1661],{},[44,3252,1071],{},[71,3254,3255,3257,3258,3260,3261,3263,3264,3266,3267,3269,3270,3273,3274,3276,3277,3279],{},[74,3256,82],{}," This is Q10's lesson applied at the API-design level: each nested async step runs in its own later callback invocation, on a call stack that no longer has the outer ",[44,3259,1516],{}," frame active, so wrapping the initiating call provides zero protection for errors surfaced via the ",[44,3262,1071],{},"-first convention — every single callback has to check its own ",[44,3265,1071],{}," and explicitly handle or forward it. Option D sounds like reasonable partial credit but is still wrong — the outer ",[44,3268,1661],{}," catches ",[578,3271,3272],{},"none"," of the async errors, not just the later ones. This exact pain point — manually re-checking ",[44,3275,1071],{}," at every level with no way to centralize it — is one of the strongest motivations for the promise-based ",[44,3278,2733],{}," model covered starting in the next quiz.",[14,3281,3282,3286,3473,3508],{"language":182},[17,3283,3285],{"id":3284},"q20-what-does-this-code-log-and-in-what-order","Q20. What does this code log, and in what order?",[188,3287,3288],{"language":182},[191,3289,3291],{"className":193,"code":3290,"language":182,"meta":195,"style":195},"console.log(\"1\");\n\nsetTimeout(() => {\n  console.log(\"2\");\n  Promise.resolve().then(() => console.log(\"3\"));\n}, 0);\n\nPromise.resolve().then(() => {\n  console.log(\"4\");\n  setTimeout(() => console.log(\"5\"), 0);\n});\n\nqueueMicrotask(() => console.log(\"6\"));\n\nconsole.log(\"7\");\n",[44,3292,3293,3306,3310,3320,3333,3360,3369,3373,3391,3404,3427,3431,3435,3454,3459],{"__ignoreMap":195},[199,3294,3295,3297,3299,3301,3304],{"class":201,"line":202},[199,3296,206],{"class":205},[199,3298,210],{"class":209},[199,3300,213],{"class":205},[199,3302,3303],{"class":216},"\"1\"",[199,3305,220],{"class":205},[199,3307,3308],{"class":201,"line":223},[199,3309,404],{"emptyLinePlaceholder":34},[199,3311,3312,3314,3316,3318],{"class":201,"line":254},[199,3313,46],{"class":209},[199,3315,228],{"class":205},[199,3317,232],{"class":231},[199,3319,895],{"class":205},[199,3321,3322,3324,3326,3328,3331],{"class":201,"line":288},[199,3323,627],{"class":205},[199,3325,210],{"class":209},[199,3327,213],{"class":205},[199,3329,3330],{"class":216},"\"2\"",[199,3332,220],{"class":205},[199,3334,3335,3337,3339,3341,3343,3345,3347,3349,3351,3353,3355,3358],{"class":201,"line":434},[199,3336,2375],{"class":248},[199,3338,260],{"class":205},[199,3340,263],{"class":209},[199,3342,266],{"class":205},[199,3344,269],{"class":209},[199,3346,228],{"class":205},[199,3348,232],{"class":231},[199,3350,235],{"class":205},[199,3352,210],{"class":209},[199,3354,213],{"class":205},[199,3356,3357],{"class":216},"\"3\"",[199,3359,285],{"class":205},[199,3361,3362,3365,3367],{"class":201,"line":446},[199,3363,3364],{"class":205},"}, ",[199,3366,249],{"class":248},[199,3368,220],{"class":205},[199,3370,3371],{"class":201,"line":470},[199,3372,404],{"emptyLinePlaceholder":34},[199,3374,3375,3377,3379,3381,3383,3385,3387,3389],{"class":201,"line":492},[199,3376,257],{"class":248},[199,3378,260],{"class":205},[199,3380,263],{"class":209},[199,3382,266],{"class":205},[199,3384,269],{"class":209},[199,3386,228],{"class":205},[199,3388,232],{"class":231},[199,3390,895],{"class":205},[199,3392,3393,3395,3397,3399,3402],{"class":201,"line":497},[199,3394,627],{"class":205},[199,3396,210],{"class":209},[199,3398,213],{"class":205},[199,3400,3401],{"class":216},"\"4\"",[199,3403,220],{"class":205},[199,3405,3406,3408,3410,3412,3414,3416,3418,3421,3423,3425],{"class":201,"line":707},[199,3407,655],{"class":209},[199,3409,228],{"class":205},[199,3411,232],{"class":231},[199,3413,235],{"class":205},[199,3415,210],{"class":209},[199,3417,213],{"class":205},[199,3419,3420],{"class":216},"\"5\"",[199,3422,245],{"class":205},[199,3424,249],{"class":248},[199,3426,220],{"class":205},[199,3428,3429],{"class":201,"line":712},[199,3430,1151],{"class":205},[199,3432,3433],{"class":201,"line":721},[199,3434,404],{"emptyLinePlaceholder":34},[199,3436,3437,3439,3441,3443,3445,3447,3449,3452],{"class":201,"line":728},[199,3438,169],{"class":209},[199,3440,228],{"class":205},[199,3442,232],{"class":231},[199,3444,235],{"class":205},[199,3446,210],{"class":209},[199,3448,213],{"class":205},[199,3450,3451],{"class":216},"\"6\"",[199,3453,285],{"class":205},[199,3455,3457],{"class":201,"line":3456},14,[199,3458,404],{"emptyLinePlaceholder":34},[199,3460,3462,3464,3466,3468,3471],{"class":201,"line":3461},15,[199,3463,206],{"class":205},[199,3465,210],{"class":209},[199,3467,213],{"class":205},[199,3469,3470],{"class":216},"\"7\"",[199,3472,220],{"class":205},[22,3474,3476,3484,3492,3500],{"className":3475},[25],[27,3477,3479,308,3481],{"className":3478},[30],[32,3480],{"disabled":34,"type":35},[44,3482,3483],{},"1, 7, 4, 6, 2, 5, 3",[27,3485,3487,308,3489],{"className":3486},[30],[32,3488],{"disabled":34,"type":35},[44,3490,3491],{},"1, 7, 4, 6, 2, 3, 5",[27,3493,3495,308,3497],{"className":3494},[30],[32,3496],{"disabled":34,"type":35},[44,3498,3499],{},"1, 4, 6, 7, 2, 3, 5",[27,3501,3503,308,3505],{"className":3502},[30],[32,3504],{"disabled":34,"type":35},[44,3506,3507],{},"1, 7, 6, 4, 2, 3, 5",[64,3509,3510,3512,3518],{},[67,3511,69],{},[71,3513,3514,552,3516],{},[74,3515,76],{},[44,3517,3491],{},[71,3519,3520,308,3522,3524,3525,173,3527,3530,3531,3533,3534,3537,3538,3540,3541,3543,3544,3547,3548,3551,3552,3554,3555,3557,3558,3560,3561,3563,3564,3567,3568,3570,3571,3573,3574,3576,3577,3579],{},[74,3521,82],{},[74,3523,561],{}," synchronous code runs first: ",[44,3526,2284],{},[44,3528,3529],{},"7",". That leaves two macrotasks queued (the first ",[44,3532,46],{},", and — later — one more once it's created) and two microtasks queued, in this order: the ",[44,3535,3536],{},"Promise.resolve().then(...)"," handler, then the ",[44,3539,169],{}," callback. Draining the microtask queue: the promise handler logs ",[44,3542,2368],{}," and, inside it, calls ",[44,3545,3546],{},"setTimeout(...)"," — this only registers a ",[578,3549,3550],{},"new macrotask",", it does not add anything to the microtask queue — so draining continues to the ",[44,3553,169],{}," callback, logging ",[44,3556,2417],{},". With microtasks now empty, the event loop runs the oldest queued macrotask (the original timeout): it logs ",[44,3559,2307],{},", then schedules a fresh ",[44,3562,3536],{},", which becomes a new microtask — and since microtasks are drained fully before the ",[578,3565,3566],{},"next"," macrotask, ",[44,3569,962],{}," logs immediately after ",[44,3572,2307],{},". Only then does the loop reach the second macrotask (queued during step ",[44,3575,2368],{},"), logging ",[44,3578,2396],{}," last. Options A and D each misplace one step by forgetting that microtasks queued mid-macrotask still drain before the following macrotask.",[3581,3582,3583],"style",{},"html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-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 .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}",{"title":195,"searchDepth":223,"depth":223,"links":3585},[3586,3587,3589,3590,3591,3592,3593,3594,3595,3597,3598,3599,3601,3603,3604,3605,3607,3609,3611,3613],{"id":19,"depth":254,"text":20},{"id":95,"depth":254,"text":3588},"Q2. Which of the following is classified as a microtask rather than a macrotask?",{"id":185,"depth":254,"text":186},{"id":378,"depth":254,"text":379},{"id":603,"depth":254,"text":604},{"id":836,"depth":254,"text":837},{"id":1052,"depth":254,"text":1053},{"id":1207,"depth":254,"text":1208},{"id":1406,"depth":254,"text":3596},"Q9. In Node.js-style APIs like fs.readFile(path, (err, data) => {...}), what does the \"error-first callback\" convention actually mean?",{"id":1503,"depth":254,"text":1504},{"id":1689,"depth":254,"text":1690},{"id":1896,"depth":254,"text":3600},"Q12. Given that the busy-wait loop below takes roughly 3 full seconds to finish, when does \"timeout fired\" actually log, relative to the requested 100ms delay?",{"id":2088,"depth":254,"text":3602},"Q13. What is the concrete risk in how loadData is written here, given that a callback's contract should specify how many times it can be invoked?",{"id":2265,"depth":254,"text":2266},{"id":2505,"depth":254,"text":2506},{"id":2670,"depth":254,"text":3606},"Q16. For sequencing several dependent async steps (fetch a user, then their posts, then comments on the first post), why do modern codebases generally avoid deeply nested callbacks in favor of promise chains (or async\u002Fawait)?",{"id":2742,"depth":254,"text":3608},"Q17. The loop below takes roughly 200ms to finish synchronously. Given that, in what order do \"A\" and \"B\" log, and why?",{"id":2940,"depth":254,"text":3610},"Q18. What does this code log, and specifically, where does \"executor\" appear in the output?",{"id":3178,"depth":254,"text":3612},"Q19. A codebase's saveUser(user, cb) internally calls three callback-based APIs in sequence, each depending on the previous result. A teammate proposes wrapping only the outermost call to saveUser in a try\u002Fcatch to handle errors from the whole chain. Why is this unsound, given the error-first callback convention from Q9?",{"id":3284,"depth":254,"text":3285},"md",{},"\u002Fjs\u002F15-callbacks-and-the-event-loop",{"title":5,"description":195},"js\u002F15-callbacks-and-the-event-loop","sGzht3JTRsfTbqt0vL2uCwIZ9hux6V5YWIX4xJQhUKA",1787335397334]