[{"data":1,"prerenderedAt":3993},["ShallowReactive",2],{"page-\u002Fjs\u002F16-promises":3},{"id":4,"title":5,"body":6,"description":103,"extension":3987,"meta":3988,"navigation":35,"path":3989,"seo":3990,"stem":3991,"__hash__":3992},"content\u002Fjs\u002F16-promises.md","16 — Promises",{"type":7,"value":8,"toc":3963},"minimark",[9,13,89,290,443,691,915,1084,1272,1466,1613,1895,2055,2330,2591,2799,2938,3120,3290,3487,3657,3959],[10,11,5],"h1",{"id":12},"_16-promises",[14,15,17,22,56],"question-wrapper",{"language":16},"javascript",[18,19,21],"h3",{"id":20},"q1-what-are-the-three-states-a-promise-can-be-in","Q1. What are the three states a Promise can be in?",[23,24,27,38,44,50],"ul",{"className":25},[26],"contains-task-list",[28,29,32,37],"li",{"className":30},[31],"task-list-item",[33,34],"input",{"disabled":35,"type":36},true,"checkbox"," waiting, resolved, errored",[28,39,41,43],{"className":40},[31],[33,42],{"disabled":35,"type":36}," pending, fulfilled, rejected",[28,45,47,49],{"className":46},[31],[33,48],{"disabled":35,"type":36}," created, running, finished",[28,51,53,55],{"className":52},[31],[33,54],{"disabled":35,"type":36}," idle, loading, settled",[57,58,59,63,71],"details",{},[60,61,62],"summary",{},"Show Answer",[64,65,66,70],"p",{},[67,68,69],"strong",{},"Answer:"," B — pending, fulfilled, rejected",[64,72,73,76,77,80,81,84,85,88],{},[67,74,75],{},"Explanation:"," Every Promise starts in the ",[67,78,79],{},"pending"," state, then transitions exactly once to either ",[67,82,83],{},"fulfilled"," (success, carries a value) or ",[67,86,87],{},"rejected"," (failure, carries a reason). There's no fourth state and no \"loading\" or \"waiting\" terminology in the spec — those are the informal names some libraries use, but the ECMAScript spec and every debugger\u002FDevTools panel use pending\u002Ffulfilled\u002Frejected.",[14,90,91,95,224,251],{"language":16},[18,92,94],{"id":93},"q2-what-does-this-log","Q2. What does this log?",[96,97,98],"code-wrapper",{"language":16},[99,100,104],"pre",{"className":101,"code":102,"language":16,"meta":103,"style":103},"language-javascript shiki shiki-themes github-light github-dark","const p = new Promise((resolve, reject) => {\n  resolve('first');\n  reject('second');\n  resolve('third');\n});\n\np.then(console.log).catch(console.log);\n","",[105,106,107,152,169,182,194,200,206],"code",{"__ignoreMap":103},[108,109,112,116,120,123,126,129,133,137,140,143,146,149],"span",{"class":110,"line":111},"line",1,[108,113,115],{"class":114},"svdQ7","const",[108,117,119],{"class":118},"snvgF"," p",[108,121,122],{"class":114}," =",[108,124,125],{"class":114}," new",[108,127,128],{"class":118}," Promise",[108,130,132],{"class":131},"ssxIu","((",[108,134,136],{"class":135},"sCrzJ","resolve",[108,138,139],{"class":131},", ",[108,141,142],{"class":135},"reject",[108,144,145],{"class":131},") ",[108,147,148],{"class":114},"=>",[108,150,151],{"class":131}," {\n",[108,153,155,159,162,166],{"class":110,"line":154},2,[108,156,158],{"class":157},"sIsaT","  resolve",[108,160,161],{"class":131},"(",[108,163,165],{"class":164},"sJ6F3","'first'",[108,167,168],{"class":131},");\n",[108,170,172,175,177,180],{"class":110,"line":171},3,[108,173,174],{"class":157},"  reject",[108,176,161],{"class":131},[108,178,179],{"class":164},"'second'",[108,181,168],{"class":131},[108,183,185,187,189,192],{"class":110,"line":184},4,[108,186,158],{"class":157},[108,188,161],{"class":131},[108,190,191],{"class":164},"'third'",[108,193,168],{"class":131},[108,195,197],{"class":110,"line":196},5,[108,198,199],{"class":131},"});\n",[108,201,203],{"class":110,"line":202},6,[108,204,205],{"emptyLinePlaceholder":35},"\n",[108,207,209,212,215,218,221],{"class":110,"line":208},7,[108,210,211],{"class":131},"p.",[108,213,214],{"class":157},"then",[108,216,217],{"class":131},"(console.log).",[108,219,220],{"class":157},"catch",[108,222,223],{"class":131},"(console.log);\n",[23,225,227,233,239,245],{"className":226},[26],[28,228,230,232],{"className":229},[31],[33,231],{"disabled":35,"type":36}," 'third'",[28,234,236,238],{"className":235},[31],[33,237],{"disabled":35,"type":36}," Throws a TypeError for calling resolve\u002Freject more than once",[28,240,242,244],{"className":241},[31],[33,243],{"disabled":35,"type":36}," 'first'",[28,246,248,250],{"className":247},[31],[33,249],{"disabled":35,"type":36}," 'second'",[57,252,253,255,260],{},[60,254,62],{},[64,256,257,259],{},[67,258,69],{}," C — 'first'",[64,261,262,264,265,268,269,272,273,275,276,278,279,281,282,285,286,289],{},[67,263,75],{}," A promise can settle ",[67,266,267],{},"only once",". The first call — ",[105,270,271],{},"resolve('first')"," — locks the promise into the fulfilled state with value ",[105,274,165],{},"; every subsequent call to ",[105,277,136],{}," or ",[105,280,142],{}," is silently ignored, no error is thrown. This is a deliberate spec guarantee: once settled, a promise's outcome is immutable, so downstream ",[105,283,284],{},".then","\u002F",[105,287,288],{},".catch"," handlers never have to worry about a value changing out from under them.",[14,291,292,296,375,404],{"language":16},[18,293,295],{"id":294},"q3-what-does-this-log","Q3. What does this log?",[96,297,298],{"language":16},[99,299,301],{"className":101,"code":300,"language":16,"meta":103,"style":103},"Promise.resolve(1)\n  .then(n => n + 1)\n  .then(n => n + 1)\n  .then(console.log);\n",[105,302,303,321,347,367],{"__ignoreMap":103},[108,304,305,308,311,313,315,318],{"class":110,"line":111},[108,306,307],{"class":118},"Promise",[108,309,310],{"class":131},".",[108,312,136],{"class":157},[108,314,161],{"class":131},[108,316,317],{"class":118},"1",[108,319,320],{"class":131},")\n",[108,322,323,326,328,330,333,336,339,342,345],{"class":110,"line":154},[108,324,325],{"class":131},"  .",[108,327,214],{"class":157},[108,329,161],{"class":131},[108,331,332],{"class":135},"n",[108,334,335],{"class":114}," =>",[108,337,338],{"class":131}," n ",[108,340,341],{"class":114},"+",[108,343,344],{"class":118}," 1",[108,346,320],{"class":131},[108,348,349,351,353,355,357,359,361,363,365],{"class":110,"line":171},[108,350,325],{"class":131},[108,352,214],{"class":157},[108,354,161],{"class":131},[108,356,332],{"class":135},[108,358,335],{"class":114},[108,360,338],{"class":131},[108,362,341],{"class":114},[108,364,344],{"class":118},[108,366,320],{"class":131},[108,368,369,371,373],{"class":110,"line":184},[108,370,325],{"class":131},[108,372,214],{"class":157},[108,374,223],{"class":131},[23,376,378,383,392,398],{"className":377},[26],[28,379,381,344],{"className":380},[31],[33,382],{"disabled":35,"type":36},[28,384,386,388,389],{"className":385},[31],[33,387],{"disabled":35,"type":36}," ",[108,390,391],{},"1, 2, 3",[28,393,395,397],{"className":394},[31],[33,396],{"disabled":35,"type":36}," undefined",[28,399,401,403],{"className":400},[31],[33,402],{"disabled":35,"type":36}," 3",[57,405,406,408,413],{},[60,407,62],{},[64,409,410,412],{},[67,411,69],{}," D — 3",[64,414,415,417,418,421,422,425,426,428,429,432,433,436,437,439,440,442],{},[67,416,75],{}," Each ",[105,419,420],{},".then()"," call returns a ",[67,423,424],{},"new promise"," whose resolved value is whatever the callback returns — that's what makes chaining work. The first ",[105,427,284],{}," returns a promise resolving to ",[105,430,431],{},"2",", the second returns one resolving to ",[105,434,435],{},"3",", and the final ",[105,438,284],{}," logs that ",[105,441,435],{},". If a callback returns a plain (non-promise) value, it's simply wrapped and passed straight to the next link.",[14,444,445,449,607,654],{"language":16},[18,446,448],{"id":447},"q4-what-does-this-log-and-in-what-order-does-the-value-arrive","Q4. What does this log, and in what order does the value arrive?",[96,450,451],{"language":16},[99,452,454],{"className":101,"code":453,"language":16,"meta":103,"style":103},"function getUser(id) {\n  return Promise.resolve({ id, name: 'Ada' });\n}\n\nfunction getOrders(user) {\n  return Promise.resolve([`order-1 for ${user.name}`]);\n}\n\ngetUser(42)\n  .then(user => getOrders(user))\n  .then(orders => console.log(orders));\n",[105,455,456,472,492,497,501,515,544,548,553,566,584],{"__ignoreMap":103},[108,457,458,461,464,466,469],{"class":110,"line":111},[108,459,460],{"class":114},"function",[108,462,463],{"class":157}," getUser",[108,465,161],{"class":131},[108,467,468],{"class":135},"id",[108,470,471],{"class":131},") {\n",[108,473,474,477,479,481,483,486,489],{"class":110,"line":154},[108,475,476],{"class":114},"  return",[108,478,128],{"class":118},[108,480,310],{"class":131},[108,482,136],{"class":157},[108,484,485],{"class":131},"({ id, name: ",[108,487,488],{"class":164},"'Ada'",[108,490,491],{"class":131}," });\n",[108,493,494],{"class":110,"line":171},[108,495,496],{"class":131},"}\n",[108,498,499],{"class":110,"line":184},[108,500,205],{"emptyLinePlaceholder":35},[108,502,503,505,508,510,513],{"class":110,"line":196},[108,504,460],{"class":114},[108,506,507],{"class":157}," getOrders",[108,509,161],{"class":131},[108,511,512],{"class":135},"user",[108,514,471],{"class":131},[108,516,517,519,521,523,525,528,531,533,535,538,541],{"class":110,"line":202},[108,518,476],{"class":114},[108,520,128],{"class":118},[108,522,310],{"class":131},[108,524,136],{"class":157},[108,526,527],{"class":131},"([",[108,529,530],{"class":164},"`order-1 for ${",[108,532,512],{"class":131},[108,534,310],{"class":164},[108,536,537],{"class":131},"name",[108,539,540],{"class":164},"}`",[108,542,543],{"class":131},"]);\n",[108,545,546],{"class":110,"line":208},[108,547,496],{"class":131},[108,549,551],{"class":110,"line":550},8,[108,552,205],{"emptyLinePlaceholder":35},[108,554,556,559,561,564],{"class":110,"line":555},9,[108,557,558],{"class":157},"getUser",[108,560,161],{"class":131},[108,562,563],{"class":118},"42",[108,565,320],{"class":131},[108,567,569,571,573,575,577,579,581],{"class":110,"line":568},10,[108,570,325],{"class":131},[108,572,214],{"class":157},[108,574,161],{"class":131},[108,576,512],{"class":135},[108,578,335],{"class":114},[108,580,507],{"class":157},[108,582,583],{"class":131},"(user))\n",[108,585,587,589,591,593,596,598,601,604],{"class":110,"line":586},11,[108,588,325],{"class":131},[108,590,214],{"class":157},[108,592,161],{"class":131},[108,594,595],{"class":135},"orders",[108,597,335],{"class":114},[108,599,600],{"class":131}," console.",[108,602,603],{"class":157},"log",[108,605,606],{"class":131},"(orders));\n",[23,608,610,619,635,643],{"className":609},[26],[28,611,613,388,615,618],{"className":612},[31],[33,614],{"disabled":35,"type":36},[108,616,617],{},"'order-1 for Ada'"," — the chain automatically waits for the inner promise before continuing",[28,620,622,624,625],{"className":621},[31],[33,623],{"disabled":35,"type":36}," Promise { ",[79,626,627,628,630,631,634],{}," } — the second ",[105,629,284],{}," runs before ",[105,632,633],{},"getOrders"," settles",[28,636,638,388,640,642],{"className":637},[31],[33,639],{"disabled":35,"type":36},[108,641,307],{}," — a promise wrapped inside an array",[28,644,646,648,649,651,652],{"className":645},[31],[33,647],{"disabled":35,"type":36}," Throws a TypeError because ",[105,650,284],{}," can't return a promise from inside another ",[105,653,284],{},[57,655,656,658,665],{},[60,657,62],{},[64,659,660,662,663,618],{},[67,661,69],{}," A — ",[108,664,617],{},[64,666,667,669,670,672,673,676,677,679,680,682,683,685,686,688,689,310],{},[67,668,75],{}," When a ",[105,671,284],{}," callback returns a promise (rather than a plain value), the chain ",[67,674,675],{},"auto-flattens",": the outer promise adopts the inner one's eventual state instead of resolving to \"a promise containing a promise.\" So the second ",[105,678,284],{}," doesn't run until ",[105,681,633],{},"'s returned promise actually settles, and it receives the unwrapped array, not a ",[105,684,307],{}," object. This is what lets you chain dependent async calls without manually nesting ",[105,687,284],{}," inside ",[105,690,284],{},[14,692,693,697,841,868],{"language":16},[18,694,696],{"id":695},"q5-what-does-this-log","Q5. What does this log?",[96,698,699],{"language":16},[99,700,702],{"className":101,"code":701,"language":16,"meta":103,"style":103},"fetchStep1()\n  .then(() => { throw new Error('boom in step 1'); })\n  .then(() => console.log('step 2'))\n  .then(() => console.log('step 3'))\n  .catch(err => console.log('caught:', err.message));\n\nfunction fetchStep1() {\n  return Promise.resolve();\n}\n",[105,703,704,712,742,764,785,810,814,824,837],{"__ignoreMap":103},[108,705,706,709],{"class":110,"line":111},[108,707,708],{"class":157},"fetchStep1",[108,710,711],{"class":131},"()\n",[108,713,714,716,718,721,723,726,729,731,734,736,739],{"class":110,"line":154},[108,715,325],{"class":131},[108,717,214],{"class":157},[108,719,720],{"class":131},"(() ",[108,722,148],{"class":114},[108,724,725],{"class":131}," { ",[108,727,728],{"class":114},"throw",[108,730,125],{"class":114},[108,732,733],{"class":157}," Error",[108,735,161],{"class":131},[108,737,738],{"class":164},"'boom in step 1'",[108,740,741],{"class":131},"); })\n",[108,743,744,746,748,750,752,754,756,758,761],{"class":110,"line":171},[108,745,325],{"class":131},[108,747,214],{"class":157},[108,749,720],{"class":131},[108,751,148],{"class":114},[108,753,600],{"class":131},[108,755,603],{"class":157},[108,757,161],{"class":131},[108,759,760],{"class":164},"'step 2'",[108,762,763],{"class":131},"))\n",[108,765,766,768,770,772,774,776,778,780,783],{"class":110,"line":184},[108,767,325],{"class":131},[108,769,214],{"class":157},[108,771,720],{"class":131},[108,773,148],{"class":114},[108,775,600],{"class":131},[108,777,603],{"class":157},[108,779,161],{"class":131},[108,781,782],{"class":164},"'step 3'",[108,784,763],{"class":131},[108,786,787,789,791,793,796,798,800,802,804,807],{"class":110,"line":196},[108,788,325],{"class":131},[108,790,220],{"class":157},[108,792,161],{"class":131},[108,794,795],{"class":135},"err",[108,797,335],{"class":114},[108,799,600],{"class":131},[108,801,603],{"class":157},[108,803,161],{"class":131},[108,805,806],{"class":164},"'caught:'",[108,808,809],{"class":131},", err.message));\n",[108,811,812],{"class":110,"line":202},[108,813,205],{"emptyLinePlaceholder":35},[108,815,816,818,821],{"class":110,"line":208},[108,817,460],{"class":114},[108,819,820],{"class":157}," fetchStep1",[108,822,823],{"class":131},"() {\n",[108,825,826,828,830,832,834],{"class":110,"line":550},[108,827,476],{"class":114},[108,829,128],{"class":118},[108,831,310],{"class":131},[108,833,136],{"class":157},[108,835,836],{"class":131},"();\n",[108,838,839],{"class":110,"line":555},[108,840,496],{"class":131},[23,842,844,850,856,862],{"className":843},[26],[28,845,847,849],{"className":846},[31],[33,848],{"disabled":35,"type":36}," 'step 2' then 'step 3'",[28,851,853,855],{"className":852},[31],[33,854],{"disabled":35,"type":36}," 'caught: boom in step 1'",[28,857,859,861],{"className":858},[31],[33,860],{"disabled":35,"type":36}," 'step 2' then 'caught: boom in step 1'",[28,863,865,867],{"className":864},[31],[33,866],{"disabled":35,"type":36}," Nothing — the error crashes the script before anything logs",[57,869,870,872,877],{},[60,871,62],{},[64,873,874,876],{},[67,875,69],{}," B — 'caught: boom in step 1'",[64,878,879,881,882,885,886,889,890,892,893,895,896,899,900,902,903,905,906,908,909,911,912,914],{},[67,880,75],{}," A single ",[105,883,884],{},".catch()"," at the end of a chain catches a rejection from ",[67,887,888],{},"any earlier link",", not just the one immediately before it. Once the first ",[105,891,284],{}," throws, the promise it returns rejects, and every subsequent ",[105,894,284],{}," in the chain is ",[67,897,898],{},"skipped"," — rejections propagate past ",[105,901,284],{}," handlers (they only have fulfillment callbacks registered) until a handler with a rejection callback (",[105,904,288],{},", or the second argument to ",[105,907,284],{},") is found. ",[105,910,760],{}," and ",[105,913,782],{}," never run.",[14,916,917,921,1024,1054],{"language":16},[18,918,920],{"id":919},"q6-what-does-this-log","Q6. What does this log?",[96,922,923],{"language":16},[99,924,926],{"className":101,"code":925,"language":16,"meta":103,"style":103},"Promise.reject(new Error('network down'))\n  .then(\n    value => console.log('fulfilled:', value),\n    err => console.log('rejected in 2nd arg:', err.message)\n  )\n  .catch(err => console.log('caught:', err.message));\n",[105,927,928,950,959,978,997,1002],{"__ignoreMap":103},[108,929,930,932,934,936,938,941,943,945,948],{"class":110,"line":111},[108,931,307],{"class":118},[108,933,310],{"class":131},[108,935,142],{"class":157},[108,937,161],{"class":131},[108,939,940],{"class":114},"new",[108,942,733],{"class":157},[108,944,161],{"class":131},[108,946,947],{"class":164},"'network down'",[108,949,763],{"class":131},[108,951,952,954,956],{"class":110,"line":154},[108,953,325],{"class":131},[108,955,214],{"class":157},[108,957,958],{"class":131},"(\n",[108,960,961,964,966,968,970,972,975],{"class":110,"line":171},[108,962,963],{"class":135},"    value",[108,965,335],{"class":114},[108,967,600],{"class":131},[108,969,603],{"class":157},[108,971,161],{"class":131},[108,973,974],{"class":164},"'fulfilled:'",[108,976,977],{"class":131},", value),\n",[108,979,980,983,985,987,989,991,994],{"class":110,"line":184},[108,981,982],{"class":135},"    err",[108,984,335],{"class":114},[108,986,600],{"class":131},[108,988,603],{"class":157},[108,990,161],{"class":131},[108,992,993],{"class":164},"'rejected in 2nd arg:'",[108,995,996],{"class":131},", err.message)\n",[108,998,999],{"class":110,"line":196},[108,1000,1001],{"class":131},"  )\n",[108,1003,1004,1006,1008,1010,1012,1014,1016,1018,1020,1022],{"class":110,"line":202},[108,1005,325],{"class":131},[108,1007,220],{"class":157},[108,1009,161],{"class":131},[108,1011,795],{"class":135},[108,1013,335],{"class":114},[108,1015,600],{"class":131},[108,1017,603],{"class":157},[108,1019,161],{"class":131},[108,1021,806],{"class":164},[108,1023,809],{"class":131},[23,1025,1027,1033,1042,1048],{"className":1026},[26],[28,1028,1030,1032],{"className":1029},[31],[33,1031],{"disabled":35,"type":36}," 'caught: network down'",[28,1034,1036,1038,1039,1041],{"className":1035},[31],[33,1037],{"disabled":35,"type":36}," Nothing — passing two arguments to ",[105,1040,284],{}," is a TypeError",[28,1043,1045,1047],{"className":1044},[31],[33,1046],{"disabled":35,"type":36}," 'rejected in 2nd arg: network down'",[28,1049,1051,1053],{"className":1050},[31],[33,1052],{"disabled":35,"type":36}," Both lines log, in that order",[57,1055,1056,1058,1063],{},[60,1057,62],{},[64,1059,1060,1062],{},[67,1061,69],{}," C — 'rejected in 2nd arg: network down'",[64,1064,1065,388,1067,1070,1071,1073,1074,1076,1077,1080,1081,1083],{},[67,1066,75],{},[105,1068,1069],{},".then(onFulfilled, onRejected)"," registers the second argument as a rejection handler for the promise ",[105,1072,284],{}," is called ON. Since the original promise is already rejected, that second-argument handler catches it directly, logs the message, and — because it doesn't throw or return a rejected promise — the promise ",[105,1075,284],{}," returns ",[67,1078,1079],{},"resolves"," (not rejects). So the trailing ",[105,1082,288],{}," has nothing to catch and never runs.",[14,1085,1086,1090,1186,1213],{"language":16},[18,1087,1089],{"id":1088},"q7-what-does-this-log","Q7. What does this log?",[96,1091,1092],{"language":16},[99,1093,1095],{"className":101,"code":1094,"language":16,"meta":103,"style":103},"Promise.resolve('ok')\n  .then(\n    value => { throw new Error('thrown inside onFulfilled'); },\n    err => console.log('rejected handler:', err.message)\n  )\n  .catch(err => console.log('caught by catch:', err.message));\n",[105,1096,1097,1112,1120,1142,1159,1163],{"__ignoreMap":103},[108,1098,1099,1101,1103,1105,1107,1110],{"class":110,"line":111},[108,1100,307],{"class":118},[108,1102,310],{"class":131},[108,1104,136],{"class":157},[108,1106,161],{"class":131},[108,1108,1109],{"class":164},"'ok'",[108,1111,320],{"class":131},[108,1113,1114,1116,1118],{"class":110,"line":154},[108,1115,325],{"class":131},[108,1117,214],{"class":157},[108,1119,958],{"class":131},[108,1121,1122,1124,1126,1128,1130,1132,1134,1136,1139],{"class":110,"line":171},[108,1123,963],{"class":135},[108,1125,335],{"class":114},[108,1127,725],{"class":131},[108,1129,728],{"class":114},[108,1131,125],{"class":114},[108,1133,733],{"class":157},[108,1135,161],{"class":131},[108,1137,1138],{"class":164},"'thrown inside onFulfilled'",[108,1140,1141],{"class":131},"); },\n",[108,1143,1144,1146,1148,1150,1152,1154,1157],{"class":110,"line":184},[108,1145,982],{"class":135},[108,1147,335],{"class":114},[108,1149,600],{"class":131},[108,1151,603],{"class":157},[108,1153,161],{"class":131},[108,1155,1156],{"class":164},"'rejected handler:'",[108,1158,996],{"class":131},[108,1160,1161],{"class":110,"line":196},[108,1162,1001],{"class":131},[108,1164,1165,1167,1169,1171,1173,1175,1177,1179,1181,1184],{"class":110,"line":202},[108,1166,325],{"class":131},[108,1168,220],{"class":157},[108,1170,161],{"class":131},[108,1172,795],{"class":135},[108,1174,335],{"class":114},[108,1176,600],{"class":131},[108,1178,603],{"class":157},[108,1180,161],{"class":131},[108,1182,1183],{"class":164},"'caught by catch:'",[108,1185,809],{"class":131},[23,1187,1189,1195,1201,1207],{"className":1188},[26],[28,1190,1192,1194],{"className":1191},[31],[33,1193],{"disabled":35,"type":36}," 'rejected handler: thrown inside onFulfilled'",[28,1196,1198,1200],{"className":1197},[31],[33,1199],{"disabled":35,"type":36}," Nothing logs — the throw is swallowed since a rejection handler was already supplied",[28,1202,1204,1206],{"className":1203},[31],[33,1205],{"disabled":35,"type":36}," Both the rejected handler and the catch run",[28,1208,1210,1212],{"className":1209},[31],[33,1211],{"disabled":35,"type":36}," 'caught by catch: thrown inside onFulfilled'",[57,1214,1215,1217,1222],{},[60,1216,62],{},[64,1218,1219,1221],{},[67,1220,69],{}," D — 'caught by catch: thrown inside onFulfilled'",[64,1223,1224,1226,1227,1229,1230,1233,1234,1236,1237,1240,1241,1244,1245,1247,1248,1251,1252,1254,1255,1257,1258,1261,1262,1265,1266,1268,1269,1271],{},[67,1225,75],{}," This is the classic two-arg-",[105,1228,284],{}," gotcha: the ",[105,1231,1232],{},"onRejected"," second argument only catches a rejection of the promise ",[105,1235,284],{}," was called on — it does ",[67,1238,1239],{},"not"," catch an error thrown from inside the ",[105,1242,1243],{},"onFulfilled"," callback sitting right next to it. Since the original promise was fulfilled, ",[105,1246,1243],{}," runs, throws, and that throw becomes a rejection of the ",[1249,1250,940],"em",{}," promise ",[105,1253,284],{}," returns — which is exactly what the chained ",[105,1256,884],{}," picks up. Using ",[105,1259,1260],{},".then(fn).catch(handler)"," instead of ",[105,1263,1264],{},".then(fn, handler)"," is the idiomatic fix precisely because ",[105,1267,288],{}," sits downstream of ",[105,1270,284],{},"'s own callback and can catch throws from within it.",[14,1273,1274,1278,1394,1421],{"language":16},[18,1275,1277],{"id":1276},"q8-what-does-this-log-and-in-what-order","Q8. What does this log, and in what order?",[96,1279,1280],{"language":16},[99,1281,1283],{"className":101,"code":1282,"language":16,"meta":103,"style":103},"Promise.resolve('data')\n  .then(val => {\n    console.log('handler:', val);\n    return val.toUpperCase();\n  })\n  .finally(() => console.log('finally ran'))\n  .then(val => console.log('after finally:', val));\n",[105,1284,1285,1300,1315,1330,1343,1348,1370],{"__ignoreMap":103},[108,1286,1287,1289,1291,1293,1295,1298],{"class":110,"line":111},[108,1288,307],{"class":118},[108,1290,310],{"class":131},[108,1292,136],{"class":157},[108,1294,161],{"class":131},[108,1296,1297],{"class":164},"'data'",[108,1299,320],{"class":131},[108,1301,1302,1304,1306,1308,1311,1313],{"class":110,"line":154},[108,1303,325],{"class":131},[108,1305,214],{"class":157},[108,1307,161],{"class":131},[108,1309,1310],{"class":135},"val",[108,1312,335],{"class":114},[108,1314,151],{"class":131},[108,1316,1317,1320,1322,1324,1327],{"class":110,"line":171},[108,1318,1319],{"class":131},"    console.",[108,1321,603],{"class":157},[108,1323,161],{"class":131},[108,1325,1326],{"class":164},"'handler:'",[108,1328,1329],{"class":131},", val);\n",[108,1331,1332,1335,1338,1341],{"class":110,"line":184},[108,1333,1334],{"class":114},"    return",[108,1336,1337],{"class":131}," val.",[108,1339,1340],{"class":157},"toUpperCase",[108,1342,836],{"class":131},[108,1344,1345],{"class":110,"line":196},[108,1346,1347],{"class":131},"  })\n",[108,1349,1350,1352,1355,1357,1359,1361,1363,1365,1368],{"class":110,"line":202},[108,1351,325],{"class":131},[108,1353,1354],{"class":157},"finally",[108,1356,720],{"class":131},[108,1358,148],{"class":114},[108,1360,600],{"class":131},[108,1362,603],{"class":157},[108,1364,161],{"class":131},[108,1366,1367],{"class":164},"'finally ran'",[108,1369,763],{"class":131},[108,1371,1372,1374,1376,1378,1380,1382,1384,1386,1388,1391],{"class":110,"line":208},[108,1373,325],{"class":131},[108,1375,214],{"class":157},[108,1377,161],{"class":131},[108,1379,1310],{"class":135},[108,1381,335],{"class":114},[108,1383,600],{"class":131},[108,1385,603],{"class":157},[108,1387,161],{"class":131},[108,1389,1390],{"class":164},"'after finally:'",[108,1392,1393],{"class":131},", val));\n",[23,1395,1397,1403,1409,1415],{"className":1396},[26],[28,1398,1400,1402],{"className":1399},[31],[33,1401],{"disabled":35,"type":36}," 'handler: data' then 'finally ran' then 'after finally: DATA'",[28,1404,1406,1408],{"className":1405},[31],[33,1407],{"disabled":35,"type":36}," 'handler: data' then 'finally ran' then 'after finally: undefined'",[28,1410,1412,1414],{"className":1411},[31],[33,1413],{"disabled":35,"type":36}," 'finally ran' then 'handler: data' then 'after finally: DATA'",[28,1416,1418,1420],{"className":1417},[31],[33,1419],{"disabled":35,"type":36}," 'handler: data' then 'after finally: DATA' then 'finally ran'",[57,1422,1423,1425,1430],{},[60,1424,62],{},[64,1426,1427,1429],{},[67,1428,69],{}," A — 'handler: data' then 'finally ran' then 'after finally: DATA'",[64,1431,1432,388,1434,1437,1438,1441,1442,1444,1445,1448,1449,1451,1452,1455,1456,1458,1459,1462,1463,1465],{},[67,1433,75],{},[105,1435,1436],{},".finally()"," runs after the preceding link settles, regardless of whether it fulfilled or rejected, but its callback receives ",[67,1439,1440],{},"no argument"," — it can't see the value or reason, and it doesn't need to, since its job is cleanup (closing a spinner, releasing a resource) rather than transforming data. Critically, ",[105,1443,1436],{}," passes the original outcome ",[67,1446,1447],{},"through unchanged"," to the next ",[105,1450,284],{},", so ",[105,1453,1454],{},"'DATA'"," survives past the ",[105,1457,1354],{}," untouched — it does not become ",[105,1460,1461],{},"undefined"," just because the ",[105,1464,1354],{}," callback returned nothing.",[14,1467,1468,1472,1543,1580],{"language":16},[18,1469,1471],{"id":1470},"q9-what-does-this-log","Q9. What does this log?",[96,1473,1474],{"language":16},[99,1475,1477],{"className":101,"code":1476,"language":16,"meta":103,"style":103},"Promise.reject(new Error('save failed'))\n  .finally(() => console.log('cleanup'))\n  .catch(err => console.log('caught:', err.message));\n",[105,1478,1479,1500,1521],{"__ignoreMap":103},[108,1480,1481,1483,1485,1487,1489,1491,1493,1495,1498],{"class":110,"line":111},[108,1482,307],{"class":118},[108,1484,310],{"class":131},[108,1486,142],{"class":157},[108,1488,161],{"class":131},[108,1490,940],{"class":114},[108,1492,733],{"class":157},[108,1494,161],{"class":131},[108,1496,1497],{"class":164},"'save failed'",[108,1499,763],{"class":131},[108,1501,1502,1504,1506,1508,1510,1512,1514,1516,1519],{"class":110,"line":154},[108,1503,325],{"class":131},[108,1505,1354],{"class":157},[108,1507,720],{"class":131},[108,1509,148],{"class":114},[108,1511,600],{"class":131},[108,1513,603],{"class":157},[108,1515,161],{"class":131},[108,1517,1518],{"class":164},"'cleanup'",[108,1520,763],{"class":131},[108,1522,1523,1525,1527,1529,1531,1533,1535,1537,1539,1541],{"class":110,"line":171},[108,1524,325],{"class":131},[108,1526,220],{"class":157},[108,1528,161],{"class":131},[108,1530,795],{"class":135},[108,1532,335],{"class":114},[108,1534,600],{"class":131},[108,1536,603],{"class":157},[108,1538,161],{"class":131},[108,1540,806],{"class":164},[108,1542,809],{"class":131},[23,1544,1546,1552,1558,1568],{"className":1545},[26],[28,1547,1549,1551],{"className":1548},[31],[33,1550],{"disabled":35,"type":36}," 'caught: save failed' then 'cleanup'",[28,1553,1555,1557],{"className":1554},[31],[33,1556],{"disabled":35,"type":36}," 'cleanup' then 'caught: save failed'",[28,1559,1561,1563,1564,1567],{"className":1560},[31],[33,1562],{"disabled":35,"type":36}," Nothing logs — ",[105,1565,1566],{},".finally"," can't be chained after a rejected promise",[28,1569,1571,1573,1574,1576,1577,1579],{"className":1570},[31],[33,1572],{"disabled":35,"type":36}," Only 'cleanup' — ",[105,1575,1566],{}," consumes the rejection so ",[105,1578,288],{}," never runs",[57,1581,1582,1584,1589],{},[60,1583,62],{},[64,1585,1586,1588],{},[67,1587,69],{}," B — 'cleanup' then 'caught: save failed'",[64,1590,1591,388,1593,1595,1596,1599,1600,1602,1603,1605,1606,1608,1609,1612],{},[67,1592,75],{},[105,1594,1436],{}," runs its callback on rejection too, but since it doesn't return a value that replaces the outcome, the original rejection ",[67,1597,1598],{},"propagates through"," to the next handler in the chain — it does not get swallowed. So ",[105,1601,1518],{}," logs first (as the finally callback fires), and the still-pending rejection then reaches ",[105,1604,288],{},", which logs the error message. The one exception (not shown here) is if the ",[105,1607,1354],{}," callback itself throws or returns a rejected promise — then ",[1249,1610,1611],{},"that"," new rejection would override the original.",[14,1614,1615,1619,1828,1862],{"language":16},[18,1616,1618],{"id":1617},"q10-three-api-calls-each-take-a-different-amount-of-time-and-one-of-them-fails-what-does-this-log","Q10. Three API calls each take a different amount of time and one of them fails. What does this log?",[96,1620,1621],{"language":16},[99,1622,1624],{"className":101,"code":1623,"language":16,"meta":103,"style":103},"const fast = new Promise(res => setTimeout(() => res('fast done'), 10));\nconst slow = new Promise(res => setTimeout(() => res('slow done'), 100));\nconst broken = new Promise((_, rej) => setTimeout(() => rej(new Error('broke')), 50));\n\nPromise.all([fast, slow, broken])\n  .then(results => console.log('all:', results))\n  .catch(err => console.log('all failed:', err.message));\n",[105,1625,1626,1670,1709,1764,1768,1780,1805],{"__ignoreMap":103},[108,1627,1628,1630,1633,1635,1637,1639,1641,1644,1646,1649,1651,1653,1656,1658,1661,1664,1667],{"class":110,"line":111},[108,1629,115],{"class":114},[108,1631,1632],{"class":118}," fast",[108,1634,122],{"class":114},[108,1636,125],{"class":114},[108,1638,128],{"class":118},[108,1640,161],{"class":131},[108,1642,1643],{"class":135},"res",[108,1645,335],{"class":114},[108,1647,1648],{"class":157}," setTimeout",[108,1650,720],{"class":131},[108,1652,148],{"class":114},[108,1654,1655],{"class":157}," res",[108,1657,161],{"class":131},[108,1659,1660],{"class":164},"'fast done'",[108,1662,1663],{"class":131},"), ",[108,1665,1666],{"class":118},"10",[108,1668,1669],{"class":131},"));\n",[108,1671,1672,1674,1677,1679,1681,1683,1685,1687,1689,1691,1693,1695,1697,1699,1702,1704,1707],{"class":110,"line":154},[108,1673,115],{"class":114},[108,1675,1676],{"class":118}," slow",[108,1678,122],{"class":114},[108,1680,125],{"class":114},[108,1682,128],{"class":118},[108,1684,161],{"class":131},[108,1686,1643],{"class":135},[108,1688,335],{"class":114},[108,1690,1648],{"class":157},[108,1692,720],{"class":131},[108,1694,148],{"class":114},[108,1696,1655],{"class":157},[108,1698,161],{"class":131},[108,1700,1701],{"class":164},"'slow done'",[108,1703,1663],{"class":131},[108,1705,1706],{"class":118},"100",[108,1708,1669],{"class":131},[108,1710,1711,1713,1716,1718,1720,1722,1724,1727,1729,1732,1734,1736,1738,1740,1742,1745,1747,1749,1751,1753,1756,1759,1762],{"class":110,"line":171},[108,1712,115],{"class":114},[108,1714,1715],{"class":118}," broken",[108,1717,122],{"class":114},[108,1719,125],{"class":114},[108,1721,128],{"class":118},[108,1723,132],{"class":131},[108,1725,1726],{"class":135},"_",[108,1728,139],{"class":131},[108,1730,1731],{"class":135},"rej",[108,1733,145],{"class":131},[108,1735,148],{"class":114},[108,1737,1648],{"class":157},[108,1739,720],{"class":131},[108,1741,148],{"class":114},[108,1743,1744],{"class":157}," rej",[108,1746,161],{"class":131},[108,1748,940],{"class":114},[108,1750,733],{"class":157},[108,1752,161],{"class":131},[108,1754,1755],{"class":164},"'broke'",[108,1757,1758],{"class":131},")), ",[108,1760,1761],{"class":118},"50",[108,1763,1669],{"class":131},[108,1765,1766],{"class":110,"line":184},[108,1767,205],{"emptyLinePlaceholder":35},[108,1769,1770,1772,1774,1777],{"class":110,"line":196},[108,1771,307],{"class":118},[108,1773,310],{"class":131},[108,1775,1776],{"class":157},"all",[108,1778,1779],{"class":131},"([fast, slow, broken])\n",[108,1781,1782,1784,1786,1788,1791,1793,1795,1797,1799,1802],{"class":110,"line":202},[108,1783,325],{"class":131},[108,1785,214],{"class":157},[108,1787,161],{"class":131},[108,1789,1790],{"class":135},"results",[108,1792,335],{"class":114},[108,1794,600],{"class":131},[108,1796,603],{"class":157},[108,1798,161],{"class":131},[108,1800,1801],{"class":164},"'all:'",[108,1803,1804],{"class":131},", results))\n",[108,1806,1807,1809,1811,1813,1815,1817,1819,1821,1823,1826],{"class":110,"line":208},[108,1808,325],{"class":131},[108,1810,220],{"class":157},[108,1812,161],{"class":131},[108,1814,795],{"class":135},[108,1816,335],{"class":114},[108,1818,600],{"class":131},[108,1820,603],{"class":157},[108,1822,161],{"class":131},[108,1824,1825],{"class":164},"'all failed:'",[108,1827,809],{"class":131},[23,1829,1831,1837,1847,1856],{"className":1830},[26],[28,1832,1834,1836],{"className":1833},[31],[33,1835],{"disabled":35,"type":36}," 'all failed: broke' — but only after all three have settled at 100ms",[28,1838,1840,1842,1843,1846],{"className":1839},[31],[33,1841],{"disabled":35,"type":36}," 'all: ",[108,1844,1845],{},"'fast done', 'slow done', undefined","'",[28,1848,1850,1852,1853],{"className":1849},[31],[33,1851],{"disabled":35,"type":36}," 'all failed: broke' — logged around the 50ms mark, without waiting for ",[105,1854,1855],{},"slow",[28,1857,1859,1861],{"className":1858},[31],[33,1860],{"disabled":35,"type":36}," Nothing logs because one promise in the array rejected",[57,1863,1864,1866,1873],{},[60,1865,62],{},[64,1867,1868,1870,1871],{},[67,1869,69],{}," C — 'all failed: broke' — logged around the 50ms mark, without waiting for ",[105,1872,1855],{},[64,1874,1875,388,1877,1880,1881,1884,1885,1887,1888,1890,1891,1894],{},[67,1876,75],{},[105,1878,1879],{},"Promise.all"," is ",[67,1882,1883],{},"fail-fast",": it rejects as soon as any single input promise rejects, immediately propagating that rejection to the ",[105,1886,288],{},", even though ",[105,1889,1855],{}," is still pending at that moment (and will keep running in the background, its eventual result simply discarded by this code). This is the key difference from ",[105,1892,1893],{},"Promise.allSettled",", which would wait for every promise to settle no matter what and never short-circuit.",[14,1896,1897,1901,1988,2022],{"language":16},[18,1898,1900],{"id":1899},"q11-what-does-this-log","Q11. What does this log?",[96,1902,1903],{"language":16},[99,1904,1906],{"className":101,"code":1905,"language":16,"meta":103,"style":103},"const results = await Promise.allSettled([\n  Promise.resolve('ok-1'),\n  Promise.reject(new Error('bad')),\n  Promise.resolve('ok-2'),\n]);\n",[105,1907,1908,1930,1947,1969,1984],{"__ignoreMap":103},[108,1909,1910,1912,1915,1917,1920,1922,1924,1927],{"class":110,"line":111},[108,1911,115],{"class":114},[108,1913,1914],{"class":118}," results",[108,1916,122],{"class":114},[108,1918,1919],{"class":114}," await",[108,1921,128],{"class":118},[108,1923,310],{"class":131},[108,1925,1926],{"class":157},"allSettled",[108,1928,1929],{"class":131},"([\n",[108,1931,1932,1935,1937,1939,1941,1944],{"class":110,"line":154},[108,1933,1934],{"class":118},"  Promise",[108,1936,310],{"class":131},[108,1938,136],{"class":157},[108,1940,161],{"class":131},[108,1942,1943],{"class":164},"'ok-1'",[108,1945,1946],{"class":131},"),\n",[108,1948,1949,1951,1953,1955,1957,1959,1961,1963,1966],{"class":110,"line":171},[108,1950,1934],{"class":118},[108,1952,310],{"class":131},[108,1954,142],{"class":157},[108,1956,161],{"class":131},[108,1958,940],{"class":114},[108,1960,733],{"class":157},[108,1962,161],{"class":131},[108,1964,1965],{"class":164},"'bad'",[108,1967,1968],{"class":131},")),\n",[108,1970,1971,1973,1975,1977,1979,1982],{"class":110,"line":184},[108,1972,1934],{"class":118},[108,1974,310],{"class":131},[108,1976,136],{"class":157},[108,1978,161],{"class":131},[108,1980,1981],{"class":164},"'ok-2'",[108,1983,1946],{"class":131},[108,1985,1986],{"class":110,"line":196},[108,1987,543],{"class":131},[23,1989,1991,1997,2006,2014],{"className":1990},[26],[28,1992,1994,1996],{"className":1993},[31],[33,1995],{"disabled":35,"type":36}," Throws because one of the promises rejected",[28,1998,2000,388,2002,2005],{"className":1999},[31],[33,2001],{"disabled":35,"type":36},[108,2003,2004],{},"'ok-1', 'ok-2'"," — rejected entries are filtered out automatically",[28,2007,2009,388,2011],{"className":2008},[31],[33,2010],{"disabled":35,"type":36},[108,2012,2013],{},"{status: 'fulfilled', value: 'ok-1'}, undefined, {status: 'fulfilled', value: 'ok-2'}",[28,2015,2017,388,2019],{"className":2016},[31],[33,2018],{"disabled":35,"type":36},[108,2020,2021],{},"{status: 'fulfilled', value: 'ok-1'}, {status: 'rejected', reason: Error('bad')}, {status: 'fulfilled', value: 'ok-2'}",[57,2023,2024,2026,2033],{},[60,2025,62],{},[64,2027,2028,2030,2031],{},[67,2029,69],{}," D — ",[108,2032,2021],{},[64,2034,2035,388,2037,2039,2040,2043,2044,2047,2048,2051,2052,2054],{},[67,2036,75],{},[105,2038,1893],{}," never short-circuits and never rejects — it waits for ",[67,2041,2042],{},"every"," input promise to settle (whether fulfilled or rejected) and resolves with an array of outcome objects, one per input, in the original order. Fulfilled entries get ",[105,2045,2046],{},"{status: 'fulfilled', value}",", rejected entries get ",[105,2049,2050],{},"{status: 'rejected', reason}",". This makes it the right tool when you need results from independent operations even if some of them fail, unlike ",[105,2053,1879],{},"'s all-or-nothing behavior.",[14,2056,2057,2061,2263,2294],{"language":16},[18,2058,2060],{"id":2059},"q12-three-mirrors-of-the-same-resource-are-raced-to-find-whichever-responds-first-what-does-this-log","Q12. Three mirrors of the same resource are raced to find whichever responds first. What does this log?",[96,2062,2063],{"language":16},[99,2064,2066],{"className":101,"code":2065,"language":16,"meta":103,"style":103},"const mirrorA = new Promise(res => setTimeout(() => res('A responded'), 200));\nconst mirrorB = new Promise((_, rej) => setTimeout(() => rej(new Error('B timed out')), 30));\nconst mirrorC = new Promise(res => setTimeout(() => res('C responded'), 150));\n\nPromise.race([mirrorA, mirrorB, mirrorC])\n  .then(v => console.log('winner:', v))\n  .catch(e => console.log('race rejected:', e.message));\n",[105,2067,2068,2107,2158,2197,2201,2213,2238],{"__ignoreMap":103},[108,2069,2070,2072,2075,2077,2079,2081,2083,2085,2087,2089,2091,2093,2095,2097,2100,2102,2105],{"class":110,"line":111},[108,2071,115],{"class":114},[108,2073,2074],{"class":118}," mirrorA",[108,2076,122],{"class":114},[108,2078,125],{"class":114},[108,2080,128],{"class":118},[108,2082,161],{"class":131},[108,2084,1643],{"class":135},[108,2086,335],{"class":114},[108,2088,1648],{"class":157},[108,2090,720],{"class":131},[108,2092,148],{"class":114},[108,2094,1655],{"class":157},[108,2096,161],{"class":131},[108,2098,2099],{"class":164},"'A responded'",[108,2101,1663],{"class":131},[108,2103,2104],{"class":118},"200",[108,2106,1669],{"class":131},[108,2108,2109,2111,2114,2116,2118,2120,2122,2124,2126,2128,2130,2132,2134,2136,2138,2140,2142,2144,2146,2148,2151,2153,2156],{"class":110,"line":154},[108,2110,115],{"class":114},[108,2112,2113],{"class":118}," mirrorB",[108,2115,122],{"class":114},[108,2117,125],{"class":114},[108,2119,128],{"class":118},[108,2121,132],{"class":131},[108,2123,1726],{"class":135},[108,2125,139],{"class":131},[108,2127,1731],{"class":135},[108,2129,145],{"class":131},[108,2131,148],{"class":114},[108,2133,1648],{"class":157},[108,2135,720],{"class":131},[108,2137,148],{"class":114},[108,2139,1744],{"class":157},[108,2141,161],{"class":131},[108,2143,940],{"class":114},[108,2145,733],{"class":157},[108,2147,161],{"class":131},[108,2149,2150],{"class":164},"'B timed out'",[108,2152,1758],{"class":131},[108,2154,2155],{"class":118},"30",[108,2157,1669],{"class":131},[108,2159,2160,2162,2165,2167,2169,2171,2173,2175,2177,2179,2181,2183,2185,2187,2190,2192,2195],{"class":110,"line":171},[108,2161,115],{"class":114},[108,2163,2164],{"class":118}," mirrorC",[108,2166,122],{"class":114},[108,2168,125],{"class":114},[108,2170,128],{"class":118},[108,2172,161],{"class":131},[108,2174,1643],{"class":135},[108,2176,335],{"class":114},[108,2178,1648],{"class":157},[108,2180,720],{"class":131},[108,2182,148],{"class":114},[108,2184,1655],{"class":157},[108,2186,161],{"class":131},[108,2188,2189],{"class":164},"'C responded'",[108,2191,1663],{"class":131},[108,2193,2194],{"class":118},"150",[108,2196,1669],{"class":131},[108,2198,2199],{"class":110,"line":184},[108,2200,205],{"emptyLinePlaceholder":35},[108,2202,2203,2205,2207,2210],{"class":110,"line":196},[108,2204,307],{"class":118},[108,2206,310],{"class":131},[108,2208,2209],{"class":157},"race",[108,2211,2212],{"class":131},"([mirrorA, mirrorB, mirrorC])\n",[108,2214,2215,2217,2219,2221,2224,2226,2228,2230,2232,2235],{"class":110,"line":202},[108,2216,325],{"class":131},[108,2218,214],{"class":157},[108,2220,161],{"class":131},[108,2222,2223],{"class":135},"v",[108,2225,335],{"class":114},[108,2227,600],{"class":131},[108,2229,603],{"class":157},[108,2231,161],{"class":131},[108,2233,2234],{"class":164},"'winner:'",[108,2236,2237],{"class":131},", v))\n",[108,2239,2240,2242,2244,2246,2249,2251,2253,2255,2257,2260],{"class":110,"line":208},[108,2241,325],{"class":131},[108,2243,220],{"class":157},[108,2245,161],{"class":131},[108,2247,2248],{"class":135},"e",[108,2250,335],{"class":114},[108,2252,600],{"class":131},[108,2254,603],{"class":157},[108,2256,161],{"class":131},[108,2258,2259],{"class":164},"'race rejected:'",[108,2261,2262],{"class":131},", e.message));\n",[23,2264,2266,2272,2278,2284],{"className":2265},[26],[28,2267,2269,2271],{"className":2268},[31],[33,2270],{"disabled":35,"type":36}," 'race rejected: B timed out'",[28,2273,2275,2277],{"className":2274},[31],[33,2276],{"disabled":35,"type":36}," 'winner: C responded'",[28,2279,2281,2283],{"className":2280},[31],[33,2282],{"disabled":35,"type":36}," 'winner: A responded'",[28,2285,2287,2289,2290,2293],{"className":2286},[31],[33,2288],{"disabled":35,"type":36}," Nothing — ",[105,2291,2292],{},"Promise.race"," requires every input to fulfill, never reject",[57,2295,2296,2298,2303],{},[60,2297,62],{},[64,2299,2300,2302],{},[67,2301,69],{}," A — 'race rejected: B timed out'",[64,2304,2305,388,2307,2309,2310,2313,2314,2317,2318,2321,2322,2325,2326,2329],{},[67,2306,75],{},[105,2308,2292],{}," settles with whichever input promise settles ",[67,2311,2312],{},"first, period"," — fulfillment and rejection are treated identically as \"settling.\" ",[105,2315,2316],{},"mirrorB"," rejects at 30ms, which is earlier than ",[105,2319,2320],{},"mirrorC","'s fulfillment at 150ms or ",[105,2323,2324],{},"mirrorA","'s at 200ms, so the race settles as a rejection even though two of the three mirrors would have eventually succeeded. This trips people up because \"race\" sounds like it should mean \"first success\" — that behavior is actually ",[105,2327,2328],{},"Promise.any",", covered next.",[14,2331,2332,2339,2527,2552],{"language":16},[18,2333,2335,2336,2338],{"id":2334},"q13-using-the-same-three-mirrors-from-the-previous-question-what-does-promiseany-produce","Q13. Using the same three mirrors from the previous question, what does ",[105,2337,2328],{}," produce?",[96,2340,2341],{"language":16},[99,2342,2344],{"className":101,"code":2343,"language":16,"meta":103,"style":103},"const mirrorA = new Promise(res => setTimeout(() => res('A responded'), 200));\nconst mirrorB = new Promise((_, rej) => setTimeout(() => rej(new Error('B timed out')), 30));\nconst mirrorC = new Promise(res => setTimeout(() => res('C responded'), 150));\n\nPromise.any([mirrorA, mirrorB, mirrorC])\n  .then(v => console.log('winner:', v))\n  .catch(e => console.log('any rejected:', e));\n",[105,2345,2346,2382,2430,2466,2470,2481,2503],{"__ignoreMap":103},[108,2347,2348,2350,2352,2354,2356,2358,2360,2362,2364,2366,2368,2370,2372,2374,2376,2378,2380],{"class":110,"line":111},[108,2349,115],{"class":114},[108,2351,2074],{"class":118},[108,2353,122],{"class":114},[108,2355,125],{"class":114},[108,2357,128],{"class":118},[108,2359,161],{"class":131},[108,2361,1643],{"class":135},[108,2363,335],{"class":114},[108,2365,1648],{"class":157},[108,2367,720],{"class":131},[108,2369,148],{"class":114},[108,2371,1655],{"class":157},[108,2373,161],{"class":131},[108,2375,2099],{"class":164},[108,2377,1663],{"class":131},[108,2379,2104],{"class":118},[108,2381,1669],{"class":131},[108,2383,2384,2386,2388,2390,2392,2394,2396,2398,2400,2402,2404,2406,2408,2410,2412,2414,2416,2418,2420,2422,2424,2426,2428],{"class":110,"line":154},[108,2385,115],{"class":114},[108,2387,2113],{"class":118},[108,2389,122],{"class":114},[108,2391,125],{"class":114},[108,2393,128],{"class":118},[108,2395,132],{"class":131},[108,2397,1726],{"class":135},[108,2399,139],{"class":131},[108,2401,1731],{"class":135},[108,2403,145],{"class":131},[108,2405,148],{"class":114},[108,2407,1648],{"class":157},[108,2409,720],{"class":131},[108,2411,148],{"class":114},[108,2413,1744],{"class":157},[108,2415,161],{"class":131},[108,2417,940],{"class":114},[108,2419,733],{"class":157},[108,2421,161],{"class":131},[108,2423,2150],{"class":164},[108,2425,1758],{"class":131},[108,2427,2155],{"class":118},[108,2429,1669],{"class":131},[108,2431,2432,2434,2436,2438,2440,2442,2444,2446,2448,2450,2452,2454,2456,2458,2460,2462,2464],{"class":110,"line":171},[108,2433,115],{"class":114},[108,2435,2164],{"class":118},[108,2437,122],{"class":114},[108,2439,125],{"class":114},[108,2441,128],{"class":118},[108,2443,161],{"class":131},[108,2445,1643],{"class":135},[108,2447,335],{"class":114},[108,2449,1648],{"class":157},[108,2451,720],{"class":131},[108,2453,148],{"class":114},[108,2455,1655],{"class":157},[108,2457,161],{"class":131},[108,2459,2189],{"class":164},[108,2461,1663],{"class":131},[108,2463,2194],{"class":118},[108,2465,1669],{"class":131},[108,2467,2468],{"class":110,"line":184},[108,2469,205],{"emptyLinePlaceholder":35},[108,2471,2472,2474,2476,2479],{"class":110,"line":196},[108,2473,307],{"class":118},[108,2475,310],{"class":131},[108,2477,2478],{"class":157},"any",[108,2480,2212],{"class":131},[108,2482,2483,2485,2487,2489,2491,2493,2495,2497,2499,2501],{"class":110,"line":202},[108,2484,325],{"class":131},[108,2486,214],{"class":157},[108,2488,161],{"class":131},[108,2490,2223],{"class":135},[108,2492,335],{"class":114},[108,2494,600],{"class":131},[108,2496,603],{"class":157},[108,2498,161],{"class":131},[108,2500,2234],{"class":164},[108,2502,2237],{"class":131},[108,2504,2505,2507,2509,2511,2513,2515,2517,2519,2521,2524],{"class":110,"line":208},[108,2506,325],{"class":131},[108,2508,220],{"class":157},[108,2510,161],{"class":131},[108,2512,2248],{"class":135},[108,2514,335],{"class":114},[108,2516,600],{"class":131},[108,2518,603],{"class":157},[108,2520,161],{"class":131},[108,2522,2523],{"class":164},"'any rejected:'",[108,2525,2526],{"class":131},", e));\n",[23,2528,2530,2536,2541,2547],{"className":2529},[26],[28,2531,2533,2535],{"className":2532},[31],[33,2534],{"disabled":35,"type":36}," 'any rejected: Error: B timed out'",[28,2537,2539,2277],{"className":2538},[31],[33,2540],{"disabled":35,"type":36},[28,2542,2544,2546],{"className":2543},[31],[33,2545],{"disabled":35,"type":36}," 'winner: B timed out'",[28,2548,2550,2283],{"className":2549},[31],[33,2551],{"disabled":35,"type":36},[57,2553,2554,2556,2561],{},[60,2555,62],{},[64,2557,2558,2560],{},[67,2559,69],{}," B — 'winner: C responded'",[64,2562,2563,388,2565,2567,2568,2571,2572,2574,2575,2578,2579,2581,2582,2584,2585,2587,2588,2590],{},[67,2564,75],{},[105,2566,2328],{}," resolves with the first promise to ",[67,2569,2570],{},"fulfill",", ignoring rejections along the way — it only rejects if ",[1249,2573,1776],{}," inputs reject (with an ",[105,2576,2577],{},"AggregateError"," collecting every individual reason). Here ",[105,2580,2316],{}," rejects at 30ms but that's not enough to settle the race; ",[105,2583,2320],{}," is the first to ",[1249,2586,2570],{},", at 150ms, so that's the winner, even though ",[105,2589,2316],{}," technically settled earlier.",[14,2592,2593,2597,2727,2766],{"language":16},[18,2594,2596],{"id":2595},"q14-all-three-mirrors-are-down-what-does-this-log","Q14. All three mirrors are down. What does this log?",[96,2598,2599],{"language":16},[99,2600,2602],{"className":101,"code":2601,"language":16,"meta":103,"style":103},"Promise.any([\n  Promise.reject(new Error('A down')),\n  Promise.reject(new Error('B down')),\n  Promise.reject(new Error('C down')),\n]).catch(err => {\n  console.log(err.name);\n  console.log(err.errors.map(e => e.message));\n});\n",[105,2603,2604,2614,2635,2656,2677,2692,2702,2723],{"__ignoreMap":103},[108,2605,2606,2608,2610,2612],{"class":110,"line":111},[108,2607,307],{"class":118},[108,2609,310],{"class":131},[108,2611,2478],{"class":157},[108,2613,1929],{"class":131},[108,2615,2616,2618,2620,2622,2624,2626,2628,2630,2633],{"class":110,"line":154},[108,2617,1934],{"class":118},[108,2619,310],{"class":131},[108,2621,142],{"class":157},[108,2623,161],{"class":131},[108,2625,940],{"class":114},[108,2627,733],{"class":157},[108,2629,161],{"class":131},[108,2631,2632],{"class":164},"'A down'",[108,2634,1968],{"class":131},[108,2636,2637,2639,2641,2643,2645,2647,2649,2651,2654],{"class":110,"line":171},[108,2638,1934],{"class":118},[108,2640,310],{"class":131},[108,2642,142],{"class":157},[108,2644,161],{"class":131},[108,2646,940],{"class":114},[108,2648,733],{"class":157},[108,2650,161],{"class":131},[108,2652,2653],{"class":164},"'B down'",[108,2655,1968],{"class":131},[108,2657,2658,2660,2662,2664,2666,2668,2670,2672,2675],{"class":110,"line":184},[108,2659,1934],{"class":118},[108,2661,310],{"class":131},[108,2663,142],{"class":157},[108,2665,161],{"class":131},[108,2667,940],{"class":114},[108,2669,733],{"class":157},[108,2671,161],{"class":131},[108,2673,2674],{"class":164},"'C down'",[108,2676,1968],{"class":131},[108,2678,2679,2682,2684,2686,2688,2690],{"class":110,"line":196},[108,2680,2681],{"class":131},"]).",[108,2683,220],{"class":157},[108,2685,161],{"class":131},[108,2687,795],{"class":135},[108,2689,335],{"class":114},[108,2691,151],{"class":131},[108,2693,2694,2697,2699],{"class":110,"line":202},[108,2695,2696],{"class":131},"  console.",[108,2698,603],{"class":157},[108,2700,2701],{"class":131},"(err.name);\n",[108,2703,2704,2706,2708,2711,2714,2716,2718,2720],{"class":110,"line":208},[108,2705,2696],{"class":131},[108,2707,603],{"class":157},[108,2709,2710],{"class":131},"(err.errors.",[108,2712,2713],{"class":157},"map",[108,2715,161],{"class":131},[108,2717,2248],{"class":135},[108,2719,335],{"class":114},[108,2721,2722],{"class":131}," e.message));\n",[108,2724,2725],{"class":110,"line":550},[108,2726,199],{"class":131},[23,2728,2730,2739,2750,2758],{"className":2729},[26],[28,2731,2733,2735,2736],{"className":2732},[31],[33,2734],{"disabled":35,"type":36}," 'Error' then ",[108,2737,2738],{},"'A down', 'B down', 'C down'",[28,2740,2742,1563,2744,2746,2747,2749],{"className":2741},[31],[33,2743],{"disabled":35,"type":36},[105,2745,288],{}," never fires because ",[105,2748,2328],{}," can't reject",[28,2751,2753,2755,2756],{"className":2752},[31],[33,2754],{"disabled":35,"type":36}," 'AggregateError' then ",[108,2757,2738],{},[28,2759,2761,2755,2763,2765],{"className":2760},[31],[33,2762],{"disabled":35,"type":36},[108,2764,2632],{},"  — only the first rejection is kept",[57,2767,2768,2770,2777],{},[60,2769,62],{},[64,2771,2772,2774,2775],{},[67,2773,69],{}," C — 'AggregateError' then ",[108,2776,2738],{},[64,2778,2779,2781,2782,2784,2785,2787,2788,2790,2791,2794,2795,2798],{},[67,2780,75],{}," When ",[67,2783,2042],{}," input to ",[105,2786,2328],{}," rejects, it rejects with a single ",[105,2789,2577],{}," whose ",[105,2792,2793],{},".errors"," property is an array holding all the individual rejection reasons in input order — not just the first or last one. This lets a caller inspect exactly why every candidate failed, unlike a plain ",[105,2796,2797],{},"Error"," which could only carry one message.",[14,2800,2801,2805,2872,2906],{"language":16},[18,2802,2804],{"id":2803},"q15-what-does-this-log","Q15. What does this log?",[96,2806,2807],{"language":16},[99,2808,2810],{"className":101,"code":2809,"language":16,"meta":103,"style":103},"const original = Promise.resolve('value');\nconst wrapped = Promise.resolve(original);\n\nconsole.log(wrapped === original);\n",[105,2811,2812,2834,2852,2856],{"__ignoreMap":103},[108,2813,2814,2816,2819,2821,2823,2825,2827,2829,2832],{"class":110,"line":111},[108,2815,115],{"class":114},[108,2817,2818],{"class":118}," original",[108,2820,122],{"class":114},[108,2822,128],{"class":118},[108,2824,310],{"class":131},[108,2826,136],{"class":157},[108,2828,161],{"class":131},[108,2830,2831],{"class":164},"'value'",[108,2833,168],{"class":131},[108,2835,2836,2838,2841,2843,2845,2847,2849],{"class":110,"line":154},[108,2837,115],{"class":114},[108,2839,2840],{"class":118}," wrapped",[108,2842,122],{"class":114},[108,2844,128],{"class":118},[108,2846,310],{"class":131},[108,2848,136],{"class":157},[108,2850,2851],{"class":131},"(original);\n",[108,2853,2854],{"class":110,"line":171},[108,2855,205],{"emptyLinePlaceholder":35},[108,2857,2858,2861,2863,2866,2869],{"class":110,"line":184},[108,2859,2860],{"class":131},"console.",[108,2862,603],{"class":157},[108,2864,2865],{"class":131},"(wrapped ",[108,2867,2868],{"class":114},"===",[108,2870,2871],{"class":131}," original);\n",[23,2873,2875,2881,2890,2900],{"className":2874},[26],[28,2876,2878,2880],{"className":2877},[31],[33,2879],{"disabled":35,"type":36}," false",[28,2882,2884,2886,2887,2889],{"className":2883},[31],[33,2885],{"disabled":35,"type":36}," undefined — comparing promises with ",[105,2888,2868],{}," always throws",[28,2891,2893,2895,2896,2899],{"className":2892},[31],[33,2894],{"disabled":35,"type":36}," false, but ",[105,2897,2898],{},"wrapped"," resolves to a Promise object rather than 'value'",[28,2901,2903,2905],{"className":2902},[31],[33,2904],{"disabled":35,"type":36}," true",[57,2907,2908,2910,2915],{},[60,2909,62],{},[64,2911,2912,2914],{},[67,2913,69],{}," D — true",[64,2916,2917,388,2919,2922,2923,2926,2927,2930,2931,2933,2934,2937],{},[67,2918,75],{},[105,2920,2921],{},"Promise.resolve()"," has a special case: if you pass it a value that is ",[67,2924,2925],{},"already a genuine promise",", it returns that exact same promise instance rather than wrapping it in a new one — there's no such thing as a \"promise of a promise\" in the spec's eyes. This differs from passing a plain ",[67,2928,2929],{},"thenable"," (a non-promise object with a ",[105,2932,284],{}," method), where ",[105,2935,2936],{},"Promise.resolve"," creates a brand-new native promise that adopts the thenable's eventual state instead of returning the thenable itself.",[14,2939,2940,2944,3047,3074],{"language":16},[18,2941,2943],{"id":2942},"q16-what-order-do-these-log-in","Q16. What order do these log in?",[96,2945,2946],{"language":16},[99,2947,2949],{"className":101,"code":2948,"language":16,"meta":103,"style":103},"console.log('1: script start');\n\nnew Promise(resolve => {\n  console.log('2: executor runs');\n  resolve('done');\n}).then(val => console.log('4: then callback,', val));\n\nconsole.log('3: script end');\n",[105,2950,2951,2964,2968,2982,2995,3006,3030,3034],{"__ignoreMap":103},[108,2952,2953,2955,2957,2959,2962],{"class":110,"line":111},[108,2954,2860],{"class":131},[108,2956,603],{"class":157},[108,2958,161],{"class":131},[108,2960,2961],{"class":164},"'1: script start'",[108,2963,168],{"class":131},[108,2965,2966],{"class":110,"line":154},[108,2967,205],{"emptyLinePlaceholder":35},[108,2969,2970,2972,2974,2976,2978,2980],{"class":110,"line":171},[108,2971,940],{"class":114},[108,2973,128],{"class":118},[108,2975,161],{"class":131},[108,2977,136],{"class":135},[108,2979,335],{"class":114},[108,2981,151],{"class":131},[108,2983,2984,2986,2988,2990,2993],{"class":110,"line":184},[108,2985,2696],{"class":131},[108,2987,603],{"class":157},[108,2989,161],{"class":131},[108,2991,2992],{"class":164},"'2: executor runs'",[108,2994,168],{"class":131},[108,2996,2997,2999,3001,3004],{"class":110,"line":196},[108,2998,158],{"class":157},[108,3000,161],{"class":131},[108,3002,3003],{"class":164},"'done'",[108,3005,168],{"class":131},[108,3007,3008,3011,3013,3015,3017,3019,3021,3023,3025,3028],{"class":110,"line":202},[108,3009,3010],{"class":131},"}).",[108,3012,214],{"class":157},[108,3014,161],{"class":131},[108,3016,1310],{"class":135},[108,3018,335],{"class":114},[108,3020,600],{"class":131},[108,3022,603],{"class":157},[108,3024,161],{"class":131},[108,3026,3027],{"class":164},"'4: then callback,'",[108,3029,1393],{"class":131},[108,3031,3032],{"class":110,"line":208},[108,3033,205],{"emptyLinePlaceholder":35},[108,3035,3036,3038,3040,3042,3045],{"class":110,"line":550},[108,3037,2860],{"class":131},[108,3039,603],{"class":157},[108,3041,161],{"class":131},[108,3043,3044],{"class":164},"'3: script end'",[108,3046,168],{"class":131},[23,3048,3050,3056,3062,3068],{"className":3049},[26],[28,3051,3053,3055],{"className":3052},[31],[33,3054],{"disabled":35,"type":36}," '1: script start', '2: executor runs', '3: script end', '4: then callback, done'",[28,3057,3059,3061],{"className":3058},[31],[33,3060],{"disabled":35,"type":36}," '1: script start', '3: script end', '2: executor runs', '4: then callback, done'",[28,3063,3065,3067],{"className":3064},[31],[33,3066],{"disabled":35,"type":36}," '1: script start', '2: executor runs', '4: then callback, done', '3: script end'",[28,3069,3071,3073],{"className":3070},[31],[33,3072],{"disabled":35,"type":36}," '2: executor runs', '1: script start', '3: script end', '4: then callback, done'",[57,3075,3076,3078,3083],{},[60,3077,62],{},[64,3079,3080,3082],{},[67,3081,69],{}," A — '1: script start', '2: executor runs', '3: script end', '4: then callback, done'",[64,3084,3085,3087,3088,3091,3092,3095,3096,3099,3100,3102,3103,3105,3106,3108,3109,3112,3113,3115,3116,3119],{},[67,3086,75],{}," The function passed to ",[105,3089,3090],{},"new Promise(...)"," — the ",[67,3093,3094],{},"executor"," — runs ",[67,3097,3098],{},"synchronously and immediately",", right when the constructor is called, not deferred to a later tick. That's why ",[105,3101,2992],{}," logs in the middle of the synchronous script, before ",[105,3104,3044],{},". But ",[105,3107,284],{}," callbacks are always deferred to the ",[67,3110,3111],{},"microtask queue",", even when the promise is already resolved by the time ",[105,3114,284],{}," is attached — so ",[105,3117,3118],{},"'4:...'"," can only run after the current synchronous run of the script finishes, landing last.",[14,3121,3122,3126,3224,3254],{"language":16},[18,3123,3125],{"id":3124},"q17-what-does-this-log","Q17. What does this log?",[96,3127,3128],{"language":16},[99,3129,3131],{"className":101,"code":3130,"language":16,"meta":103,"style":103},"const p = new Promise((resolve, reject) => {\n  JSON.parse('{ this is not valid json');\n  resolve('never reached');\n});\n\np.catch(err => console.log('caught:', err.constructor.name));\n",[105,3132,3133,3159,3176,3187,3191,3195],{"__ignoreMap":103},[108,3134,3135,3137,3139,3141,3143,3145,3147,3149,3151,3153,3155,3157],{"class":110,"line":111},[108,3136,115],{"class":114},[108,3138,119],{"class":118},[108,3140,122],{"class":114},[108,3142,125],{"class":114},[108,3144,128],{"class":118},[108,3146,132],{"class":131},[108,3148,136],{"class":135},[108,3150,139],{"class":131},[108,3152,142],{"class":135},[108,3154,145],{"class":131},[108,3156,148],{"class":114},[108,3158,151],{"class":131},[108,3160,3161,3164,3166,3169,3171,3174],{"class":110,"line":154},[108,3162,3163],{"class":118},"  JSON",[108,3165,310],{"class":131},[108,3167,3168],{"class":157},"parse",[108,3170,161],{"class":131},[108,3172,3173],{"class":164},"'{ this is not valid json'",[108,3175,168],{"class":131},[108,3177,3178,3180,3182,3185],{"class":110,"line":171},[108,3179,158],{"class":157},[108,3181,161],{"class":131},[108,3183,3184],{"class":164},"'never reached'",[108,3186,168],{"class":131},[108,3188,3189],{"class":110,"line":184},[108,3190,199],{"class":131},[108,3192,3193],{"class":110,"line":196},[108,3194,205],{"emptyLinePlaceholder":35},[108,3196,3197,3199,3201,3203,3205,3207,3209,3211,3213,3215,3218,3221],{"class":110,"line":202},[108,3198,211],{"class":131},[108,3200,220],{"class":157},[108,3202,161],{"class":131},[108,3204,795],{"class":135},[108,3206,335],{"class":114},[108,3208,600],{"class":131},[108,3210,603],{"class":157},[108,3212,161],{"class":131},[108,3214,806],{"class":164},[108,3216,3217],{"class":131},", err.",[108,3219,3220],{"class":118},"constructor",[108,3222,3223],{"class":131},".name));\n",[23,3225,3227,3233,3239,3248],{"className":3226},[26],[28,3228,3230,3232],{"className":3229},[31],[33,3231],{"disabled":35,"type":36}," Nothing — the malformed JSON crashes the script since it's thrown outside a try\u002Fcatch",[28,3234,3236,3238],{"className":3235},[31],[33,3237],{"disabled":35,"type":36}," 'caught: SyntaxError'",[28,3240,3242,3244,3245,3247],{"className":3241},[31],[33,3243],{"disabled":35,"type":36}," The promise stays pending forever because ",[105,3246,142],{}," was never explicitly called",[28,3249,3251,3253],{"className":3250},[31],[33,3252],{"disabled":35,"type":36}," 'caught: undefined'",[57,3255,3256,3258,3263],{},[60,3257,62],{},[64,3259,3260,3262],{},[67,3261,69],{}," B — 'caught: SyntaxError'",[64,3264,3265,3267,3268,3271,3272,3275,3276,3279,3280,3283,3284,3286,3287,3289],{},[67,3266,75],{}," Any synchronous throw inside a promise executor is ",[67,3269,3270],{},"automatically caught by the Promise machinery itself"," and converted into a rejection with that thrown value as the reason — you don't need your own try\u002Fcatch inside the executor. ",[105,3273,3274],{},"JSON.parse"," throws a ",[105,3277,3278],{},"SyntaxError"," on malformed input, that throw never reaches ",[105,3281,3282],{},"resolve('never reached')",", and the promise settles as rejected with the ",[105,3285,3278],{}," as its reason, which ",[105,3288,288],{}," then receives.",[14,3291,3292,3299,3400,3443],{"language":16},[18,3293,3295,3296,3298],{"id":3294},"q18-this-promise-chain-has-no-catch-anywhere-whats-the-most-accurate-description-of-what-happens-when-it-runs-eg-in-a-browser","Q18. This promise chain has no ",[105,3297,884],{}," anywhere. What's the most accurate description of what happens when it runs (e.g., in a browser)?",[96,3300,3301],{"language":16},[99,3302,3304],{"className":101,"code":3303,"language":16,"meta":103,"style":103},"function loadUserProfile(id) {\n  return fetch(`\u002Fapi\u002Fusers\u002F${id}`)\n    .then(res => res.json())\n    .then(data => data.profile.avatarUrl.toUpperCase());\n}\n\nloadUserProfile(999);\n",[105,3305,3306,3319,3337,3359,3380,3384,3388],{"__ignoreMap":103},[108,3307,3308,3310,3313,3315,3317],{"class":110,"line":111},[108,3309,460],{"class":114},[108,3311,3312],{"class":157}," loadUserProfile",[108,3314,161],{"class":131},[108,3316,468],{"class":135},[108,3318,471],{"class":131},[108,3320,3321,3323,3326,3328,3331,3333,3335],{"class":110,"line":154},[108,3322,476],{"class":114},[108,3324,3325],{"class":157}," fetch",[108,3327,161],{"class":131},[108,3329,3330],{"class":164},"`\u002Fapi\u002Fusers\u002F${",[108,3332,468],{"class":131},[108,3334,540],{"class":164},[108,3336,320],{"class":131},[108,3338,3339,3342,3344,3346,3348,3350,3353,3356],{"class":110,"line":171},[108,3340,3341],{"class":131},"    .",[108,3343,214],{"class":157},[108,3345,161],{"class":131},[108,3347,1643],{"class":135},[108,3349,335],{"class":114},[108,3351,3352],{"class":131}," res.",[108,3354,3355],{"class":157},"json",[108,3357,3358],{"class":131},"())\n",[108,3360,3361,3363,3365,3367,3370,3372,3375,3377],{"class":110,"line":184},[108,3362,3341],{"class":131},[108,3364,214],{"class":157},[108,3366,161],{"class":131},[108,3368,3369],{"class":135},"data",[108,3371,335],{"class":114},[108,3373,3374],{"class":131}," data.profile.avatarUrl.",[108,3376,1340],{"class":157},[108,3378,3379],{"class":131},"());\n",[108,3381,3382],{"class":110,"line":196},[108,3383,496],{"class":131},[108,3385,3386],{"class":110,"line":202},[108,3387,205],{"emptyLinePlaceholder":35},[108,3389,3390,3393,3395,3398],{"class":110,"line":208},[108,3391,3392],{"class":157},"loadUserProfile",[108,3394,161],{"class":131},[108,3396,3397],{"class":118},"999",[108,3399,168],{"class":131},[23,3401,3403,3412,3422,3432],{"className":3402},[26],[28,3404,3406,3408,3409,3411],{"className":3405},[31],[33,3407],{"disabled":35,"type":36}," JavaScript automatically logs the error to the console and continues as if ",[105,3410,288],{}," had been attached",[28,3413,3415,3417,3418,3421],{"className":3414},[31],[33,3416],{"disabled":35,"type":36}," The entire script halts immediately at ",[105,3419,3420],{},"loadUserProfile(999)",", exactly like an uncaught synchronous throw",[28,3423,3425,3427,3428,3431],{"className":3424},[31],[33,3426],{"disabled":35,"type":36}," If any link in the chain rejects, the rejection goes unhandled: the runtime fires an ",[105,3429,3430],{},"unhandledrejection"," event (and Node can be configured to crash the process on it), but the error is otherwise silently swallowed from the caller's perspective",[28,3433,3435,3437,3438,3440,3441],{"className":3434},[31],[33,3436],{"disabled":35,"type":36}," Nothing special happens — a promise chain without ",[105,3439,288],{}," behaves identically to one with ",[105,3442,288],{},[57,3444,3445,3447,3454],{},[60,3446,62],{},[64,3448,3449,3451,3452,3431],{},[67,3450,69],{}," C — If any link in the chain rejects, the rejection goes unhandled: the runtime fires an ",[105,3453,3430],{},[64,3455,3456,3458,3459,3461,3462,3465,3466,3469,3470,3473,3474,3476,3477,3480,3481,3483,3484,3486],{},[67,3457,75],{}," Without a terminal ",[105,3460,884],{}," (or a rejection handler somewhere downstream), a rejection anywhere in this chain — a network failure, a missing ",[105,3463,3464],{},"profile"," field making ",[105,3467,3468],{},".avatarUrl"," throw — becomes an ",[67,3471,3472],{},"unhandled rejection",". Browsers surface this via the ",[105,3475,3430],{}," event on ",[105,3478,3479],{},"window"," (usually just a console warning); Node.js emits the same event and, depending on configuration, can terminate the process. Critically, the calling code (",[105,3482,3420],{}," here) gets no synchronous exception and no return value indicating failure — the error simply vanishes from the caller's point of view unless something is listening for that event or a ",[105,3485,288],{}," exists in the chain.",[14,3488,3489,3493,3559,3610],{"language":16},[18,3490,3492],{"id":3491},"q19-which-change-makes-this-function-follow-best-practice-for-promise-based-error-handling","Q19. Which change makes this function follow best practice for promise-based error handling?",[96,3494,3495],{"language":16},[99,3496,3498],{"className":101,"code":3497,"language":16,"meta":103,"style":103},"function saveDraft(doc) {\n  db.write(doc)\n    .then(() => notifyAutosaveSuccess())\n    .then(() => updateLastSavedTimestamp());\n}\n",[105,3499,3500,3514,3525,3540,3555],{"__ignoreMap":103},[108,3501,3502,3504,3507,3509,3512],{"class":110,"line":111},[108,3503,460],{"class":114},[108,3505,3506],{"class":157}," saveDraft",[108,3508,161],{"class":131},[108,3510,3511],{"class":135},"doc",[108,3513,471],{"class":131},[108,3515,3516,3519,3522],{"class":110,"line":154},[108,3517,3518],{"class":131},"  db.",[108,3520,3521],{"class":157},"write",[108,3523,3524],{"class":131},"(doc)\n",[108,3526,3527,3529,3531,3533,3535,3538],{"class":110,"line":171},[108,3528,3341],{"class":131},[108,3530,214],{"class":157},[108,3532,720],{"class":131},[108,3534,148],{"class":114},[108,3536,3537],{"class":157}," notifyAutosaveSuccess",[108,3539,3358],{"class":131},[108,3541,3542,3544,3546,3548,3550,3553],{"class":110,"line":184},[108,3543,3341],{"class":131},[108,3545,214],{"class":157},[108,3547,720],{"class":131},[108,3549,148],{"class":114},[108,3551,3552],{"class":157}," updateLastSavedTimestamp",[108,3554,3379],{"class":131},[108,3556,3557],{"class":110,"line":196},[108,3558,496],{"class":131},[23,3560,3562,3571,3583,3593],{"className":3561},[26],[28,3563,3565,3567,3568,3570],{"className":3564},[31],[33,3566],{"disabled":35,"type":36}," Nothing needs to change — chains without ",[105,3569,288],{}," are fine as long as the individual functions don't throw",[28,3572,3574,3576,3577,3579,3580,3582],{"className":3573},[31],[33,3575],{"disabled":35,"type":36}," Replace ",[105,3578,284],{}," with ",[105,3581,1566],{}," on every step so failures are automatically retried",[28,3584,3586,3588,3589,3592],{"className":3585},[31],[33,3587],{"disabled":35,"type":36}," Wrap the whole function body in ",[105,3590,3591],{},"try { } catch { }"," instead — that's sufficient to catch promise rejections",[28,3594,3596,3598,3599,3601,3602,3605,3606,3609],{"className":3595},[31],[33,3597],{"disabled":35,"type":36}," Add a ",[105,3600,884],{}," at the end of the chain (and ",[105,3603,3604],{},"return"," the chain) so a failure in ",[105,3607,3608],{},"db.write",", the notify step, or the timestamp update is handled instead of becoming an unhandled rejection",[57,3611,3612,3614,3625],{},[60,3613,62],{},[64,3615,3616,3618,3619,3601,3621,3605,3623,3609],{},[67,3617,69],{}," D — Add a ",[105,3620,884],{},[105,3622,3604],{},[105,3624,3608],{},[64,3626,3627,388,3629,3632,3633,3635,3636,3639,3640,3643,3644,3646,3647,3650,3651,3653,3654,3656],{},[67,3628,75],{},[67,3630,3631],{},"Idiom:"," every promise chain should terminate in a ",[105,3634,884],{}," (or otherwise have its rejection handled by the caller) — otherwise a failure at any link becomes an unhandled rejection that silently disappears instead of being logged, retried, or surfaced to the user. A plain synchronous ",[105,3637,3638],{},"try\u002Fcatch"," wrapped around code that merely ",[1249,3641,3642],{},"starts"," a promise chain does ",[67,3645,1239],{}," catch asynchronous rejections that happen later, since the ",[105,3648,3649],{},"try"," block has already finished executing by the time ",[105,3652,284],{}," callbacks run — that's a common misconception. ",[105,3655,1566],{}," is for cleanup, not retries, and doesn't handle rejections either.",[14,3658,3659,3663,3886,3916],{"language":16},[18,3660,3662],{"id":3661},"q20-what-does-this-log","Q20. What does this log?",[96,3664,3665],{"language":16},[99,3666,3668],{"className":101,"code":3667,"language":16,"meta":103,"style":103},"function chargeCard(amount) {\n  return new Promise((resolve, reject) => {\n    if (amount \u003C= 0) {\n      reject(new Error('invalid amount'));\n      return;\n    }\n    resolve(`charged $${amount}`);\n  });\n}\n\nchargeCard(-5)\n  .then(receipt => receipt)\n  .then(receipt => console.log('receipt:', receipt))\n  .catch(err => console.log('charge failed:', err.message))\n  .then(() => console.log('cleanup: closing dialog'));\n",[105,3669,3670,3684,3706,3722,3740,3748,3753,3769,3774,3778,3782,3797,3814,3839,3864],{"__ignoreMap":103},[108,3671,3672,3674,3677,3679,3682],{"class":110,"line":111},[108,3673,460],{"class":114},[108,3675,3676],{"class":157}," chargeCard",[108,3678,161],{"class":131},[108,3680,3681],{"class":135},"amount",[108,3683,471],{"class":131},[108,3685,3686,3688,3690,3692,3694,3696,3698,3700,3702,3704],{"class":110,"line":154},[108,3687,476],{"class":114},[108,3689,125],{"class":114},[108,3691,128],{"class":118},[108,3693,132],{"class":131},[108,3695,136],{"class":135},[108,3697,139],{"class":131},[108,3699,142],{"class":135},[108,3701,145],{"class":131},[108,3703,148],{"class":114},[108,3705,151],{"class":131},[108,3707,3708,3711,3714,3717,3720],{"class":110,"line":171},[108,3709,3710],{"class":114},"    if",[108,3712,3713],{"class":131}," (amount ",[108,3715,3716],{"class":114},"\u003C=",[108,3718,3719],{"class":118}," 0",[108,3721,471],{"class":131},[108,3723,3724,3727,3729,3731,3733,3735,3738],{"class":110,"line":184},[108,3725,3726],{"class":157},"      reject",[108,3728,161],{"class":131},[108,3730,940],{"class":114},[108,3732,733],{"class":157},[108,3734,161],{"class":131},[108,3736,3737],{"class":164},"'invalid amount'",[108,3739,1669],{"class":131},[108,3741,3742,3745],{"class":110,"line":196},[108,3743,3744],{"class":114},"      return",[108,3746,3747],{"class":131},";\n",[108,3749,3750],{"class":110,"line":202},[108,3751,3752],{"class":131},"    }\n",[108,3754,3755,3758,3760,3763,3765,3767],{"class":110,"line":208},[108,3756,3757],{"class":157},"    resolve",[108,3759,161],{"class":131},[108,3761,3762],{"class":164},"`charged $${",[108,3764,3681],{"class":131},[108,3766,540],{"class":164},[108,3768,168],{"class":131},[108,3770,3771],{"class":110,"line":550},[108,3772,3773],{"class":131},"  });\n",[108,3775,3776],{"class":110,"line":555},[108,3777,496],{"class":131},[108,3779,3780],{"class":110,"line":568},[108,3781,205],{"emptyLinePlaceholder":35},[108,3783,3784,3787,3789,3792,3795],{"class":110,"line":586},[108,3785,3786],{"class":157},"chargeCard",[108,3788,161],{"class":131},[108,3790,3791],{"class":114},"-",[108,3793,3794],{"class":118},"5",[108,3796,320],{"class":131},[108,3798,3800,3802,3804,3806,3809,3811],{"class":110,"line":3799},12,[108,3801,325],{"class":131},[108,3803,214],{"class":157},[108,3805,161],{"class":131},[108,3807,3808],{"class":135},"receipt",[108,3810,335],{"class":114},[108,3812,3813],{"class":131}," receipt)\n",[108,3815,3817,3819,3821,3823,3825,3827,3829,3831,3833,3836],{"class":110,"line":3816},13,[108,3818,325],{"class":131},[108,3820,214],{"class":157},[108,3822,161],{"class":131},[108,3824,3808],{"class":135},[108,3826,335],{"class":114},[108,3828,600],{"class":131},[108,3830,603],{"class":157},[108,3832,161],{"class":131},[108,3834,3835],{"class":164},"'receipt:'",[108,3837,3838],{"class":131},", receipt))\n",[108,3840,3842,3844,3846,3848,3850,3852,3854,3856,3858,3861],{"class":110,"line":3841},14,[108,3843,325],{"class":131},[108,3845,220],{"class":157},[108,3847,161],{"class":131},[108,3849,795],{"class":135},[108,3851,335],{"class":114},[108,3853,600],{"class":131},[108,3855,603],{"class":157},[108,3857,161],{"class":131},[108,3859,3860],{"class":164},"'charge failed:'",[108,3862,3863],{"class":131},", err.message))\n",[108,3865,3867,3869,3871,3873,3875,3877,3879,3881,3884],{"class":110,"line":3866},15,[108,3868,325],{"class":131},[108,3870,214],{"class":157},[108,3872,720],{"class":131},[108,3874,148],{"class":114},[108,3876,600],{"class":131},[108,3878,603],{"class":157},[108,3880,161],{"class":131},[108,3882,3883],{"class":164},"'cleanup: closing dialog'",[108,3885,1669],{"class":131},[23,3887,3889,3895,3901,3910],{"className":3888},[26],[28,3890,3892,3894],{"className":3891},[31],[33,3893],{"disabled":35,"type":36}," 'charge failed: invalid amount' then 'cleanup: closing dialog'",[28,3896,3898,3900],{"className":3897},[31],[33,3899],{"disabled":35,"type":36}," 'receipt: undefined' then 'cleanup: closing dialog'",[28,3902,3904,3906,3907,3909],{"className":3903},[31],[33,3905],{"disabled":35,"type":36}," 'charge failed: invalid amount' — the final ",[105,3908,284],{}," never runs because the chain already rejected",[28,3911,3913,3915],{"className":3912},[31],[33,3914],{"disabled":35,"type":36}," 'cleanup: closing dialog' then 'charge failed: invalid amount'",[57,3917,3918,3920,3925],{},[60,3919,62],{},[64,3921,3922,3924],{},[67,3923,69],{}," A — 'charge failed: invalid amount' then 'cleanup: closing dialog'",[64,3926,3927,388,3929,3932,3933,3936,3937,3939,3940,3942,3943,3945,3946,3949,3950,3952,3953,3955,3956,3958],{},[67,3928,75],{},[105,3930,3931],{},"chargeCard(-5)"," rejects, so both intermediate ",[105,3934,3935],{},".then(receipt => receipt)"," calls are skipped (rejections skip past ",[105,3938,284],{}," handlers with no rejection callback) until ",[105,3941,288],{}," picks it up and logs the message. Since that ",[105,3944,288],{}," callback returns normally (doesn't throw or return a rejected promise), the promise it produces ",[67,3947,3948],{},"fulfills",", so the chain is back in the \"happy path\" — the final ",[105,3951,284],{}," runs normally and logs the cleanup line. This is the same \"catch resets the chain to fulfilled\" mechanism that lets a single ",[105,3954,288],{}," recover from an error and let subsequent ",[105,3957,284],{}," steps continue.",[3960,3961,3962],"style",{},"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 pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}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 .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);}",{"title":103,"searchDepth":154,"depth":154,"links":3964},[3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,3979,3980,3981,3982,3983,3985,3986],{"id":20,"depth":171,"text":21},{"id":93,"depth":171,"text":94},{"id":294,"depth":171,"text":295},{"id":447,"depth":171,"text":448},{"id":695,"depth":171,"text":696},{"id":919,"depth":171,"text":920},{"id":1088,"depth":171,"text":1089},{"id":1276,"depth":171,"text":1277},{"id":1470,"depth":171,"text":1471},{"id":1617,"depth":171,"text":1618},{"id":1899,"depth":171,"text":1900},{"id":2059,"depth":171,"text":2060},{"id":2334,"depth":171,"text":3978},"Q13. Using the same three mirrors from the previous question, what does Promise.any produce?",{"id":2595,"depth":171,"text":2596},{"id":2803,"depth":171,"text":2804},{"id":2942,"depth":171,"text":2943},{"id":3124,"depth":171,"text":3125},{"id":3294,"depth":171,"text":3984},"Q18. This promise chain has no .catch() anywhere. What's the most accurate description of what happens when it runs (e.g., in a browser)?",{"id":3491,"depth":171,"text":3492},{"id":3661,"depth":171,"text":3662},"md",{},"\u002Fjs\u002F16-promises",{"title":5,"description":103},"js\u002F16-promises","qXj4mbOH14QUqDCu0jI3imY5lsWvGA0bHUfr0-_wba8",1787335397335]