[{"data":1,"prerenderedAt":3322},["ShallowReactive",2],{"en-post-\u002Fen\u002Fjavascript-async-error-handling":3},{"id":4,"title":5,"body":6,"description":3310,"extension":3311,"meta":3312,"navigation":85,"path":3317,"seo":3318,"sitemap":3319,"stem":3320,"__hash__":3321},"blogEn\u002Fen\u002Fjavascript-async-error-handling.md","Handling Async Errors in JavaScript Correctly: From What try\u002Fcatch Misses to Promise.all vs allSettled",{"type":7,"value":8,"toc":3283},"minimark",[9,14,23,157,165,186,237,257,260,263,275,287,443,468,470,478,490,572,575,680,691,693,701,710,787,790,2343,2358,2363,2417,2419,2426,2436,2542,2554,2562,2643,2651,2672,2674,2678,2686,2773,2783,2928,2931,2933,2937,2944,2950,3013,3017,3051,3061,3068,3071,3115,3126,3128,3132,3257,3279],[10,11,13],"h2",{"id":12},"you-wrapped-it-in-trycatch-why-does-the-error-still-escape","You wrapped it in try\u002Fcatch. Why does the error still escape?",[15,16,17,18,22],"p",{},"You wrap a data-loading function in ",[19,20,21],"code",{},"try\u002Fcatch",", but the error isn't caught.",[24,25,30],"pre",{"className":26,"code":27,"language":28,"meta":29,"style":29},"language-js shiki shiki-themes github-light github-dark","async function load() {\n  throw new Error(\"Server error\");\n}\n\ntry {\n  load();\n  console.log(\"Got through the try block\");\n} catch (e) {\n  console.log(\"Caught\", e.message); \u002F\u002F never runs\n}\n","js","",[19,31,32,52,74,80,87,96,105,121,133,152],{"__ignoreMap":29},[33,34,37,41,44,48],"span",{"class":35,"line":36},"line",1,[33,38,40],{"class":39},"szBVR","async",[33,42,43],{"class":39}," function",[33,45,47],{"class":46},"sScJk"," load",[33,49,51],{"class":50},"sVt8B","() {\n",[33,53,55,58,61,64,67,71],{"class":35,"line":54},2,[33,56,57],{"class":39},"  throw",[33,59,60],{"class":39}," new",[33,62,63],{"class":46}," Error",[33,65,66],{"class":50},"(",[33,68,70],{"class":69},"sZZnC","\"Server error\"",[33,72,73],{"class":50},");\n",[33,75,77],{"class":35,"line":76},3,[33,78,79],{"class":50},"}\n",[33,81,83],{"class":35,"line":82},4,[33,84,86],{"emptyLinePlaceholder":85},true,"\n",[33,88,90,93],{"class":35,"line":89},5,[33,91,92],{"class":39},"try",[33,94,95],{"class":50}," {\n",[33,97,99,102],{"class":35,"line":98},6,[33,100,101],{"class":46},"  load",[33,103,104],{"class":50},"();\n",[33,106,108,111,114,116,119],{"class":35,"line":107},7,[33,109,110],{"class":50},"  console.",[33,112,113],{"class":46},"log",[33,115,66],{"class":50},[33,117,118],{"class":69},"\"Got through the try block\"",[33,120,73],{"class":50},[33,122,124,127,130],{"class":35,"line":123},8,[33,125,126],{"class":50},"} ",[33,128,129],{"class":39},"catch",[33,131,132],{"class":50}," (e) {\n",[33,134,136,138,140,142,145,148],{"class":35,"line":135},9,[33,137,110],{"class":50},[33,139,113],{"class":46},[33,141,66],{"class":50},[33,143,144],{"class":69},"\"Caught\"",[33,146,147],{"class":50},", e.message); ",[33,149,151],{"class":150},"sJ8bj","\u002F\u002F never runs\n",[33,153,155],{"class":35,"line":154},10,[33,156,79],{"class":50},[24,158,163],{"className":159,"code":161,"language":162},[160],"language-text","Got through the try block\nUncaught (in promise) Error: Server error\n","text",[19,164,161],{"__ignoreMap":29},[15,166,167,168,170,171,175,176,179,180,182,183,185],{},"An ",[19,169,40],{}," function doesn't ",[172,173,174],"strong",{},"throw"," errors; it ",[172,177,178],{},"returns"," a rejected Promise. The ",[19,181,92],{}," block finishes as soon as it receives the Promise, and the error surfaces later inside the Promise, so ",[19,184,129],{}," never gets a chance.",[24,187,189],{"className":26,"code":188,"language":28,"meta":29,"style":29},"try {\n  await load(); \u002F\u002F ✅ await turns the rejected Promise into a thrown error that reaches catch\n} catch (e) {\n  console.log(\"Caught\", e.message); \u002F\u002F \"Caught Server error\"\n}\n",[19,190,191,197,210,218,233],{"__ignoreMap":29},[33,192,193,195],{"class":35,"line":36},[33,194,92],{"class":39},[33,196,95],{"class":50},[33,198,199,202,204,207],{"class":35,"line":54},[33,200,201],{"class":39},"  await",[33,203,47],{"class":46},[33,205,206],{"class":50},"(); ",[33,208,209],{"class":150},"\u002F\u002F ✅ await turns the rejected Promise into a thrown error that reaches catch\n",[33,211,212,214,216],{"class":35,"line":76},[33,213,126],{"class":50},[33,215,129],{"class":39},[33,217,132],{"class":50},[33,219,220,222,224,226,228,230],{"class":35,"line":82},[33,221,110],{"class":50},[33,223,113],{"class":46},[33,225,66],{"class":50},[33,227,144],{"class":69},[33,229,147],{"class":50},[33,231,232],{"class":150},"\u002F\u002F \"Caught Server error\"\n",[33,234,235],{"class":35,"line":89},[33,236,79],{"class":50},[238,239,240],"blockquote",{},[15,241,242,243,245,246,253,254,256],{},"To catch async errors with ",[19,244,21],{},", ",[172,247,248,249,252],{},"you must ",[19,250,251],{},"await","."," ",[19,255,251],{}," is the bridge that turns a rejected Promise into a thrown error.",[15,258,259],{},"Most async error handling falls apart in traps like this, where you think there's a safety net and there isn't. Let's go through them one by one.",[261,262],"hr",{},[10,264,266,267,270,271,274],{"id":265},"trap-1-return-and-return-await-are-different","Trap 1. ",[19,268,269],{},"return"," and ",[19,272,273],{},"return await"," are different",[15,276,277,278,280,281,283,284,286],{},"If you just ",[19,279,269],{}," a Promise inside ",[19,282,92],{},", this function's ",[19,285,129],{}," won't run even when that Promise fails.",[24,288,290],{"className":26,"code":289,"language":28,"meta":29,"style":29},"async function a1() {\n  try {\n    return load(); \u002F\u002F ❌ hands the Promise straight through and the function ends\n  } catch (e) {\n    return \"fallback\";\n  }\n}\n\nasync function a2() {\n  try {\n    return await load(); \u002F\u002F ✅ waits here, so a failure lands in catch\n  } catch (e) {\n    return \"fallback\";\n  }\n}\n\nawait a1(); \u002F\u002F Error: Server error (catch is skipped)\nawait a2(); \u002F\u002F \"fallback\"\n",[19,291,292,303,310,322,331,341,346,350,354,365,371,386,395,404,409,414,419,431],{"__ignoreMap":29},[33,293,294,296,298,301],{"class":35,"line":36},[33,295,40],{"class":39},[33,297,43],{"class":39},[33,299,300],{"class":46}," a1",[33,302,51],{"class":50},[33,304,305,308],{"class":35,"line":54},[33,306,307],{"class":39},"  try",[33,309,95],{"class":50},[33,311,312,315,317,319],{"class":35,"line":76},[33,313,314],{"class":39},"    return",[33,316,47],{"class":46},[33,318,206],{"class":50},[33,320,321],{"class":150},"\u002F\u002F ❌ hands the Promise straight through and the function ends\n",[33,323,324,327,329],{"class":35,"line":82},[33,325,326],{"class":50},"  } ",[33,328,129],{"class":39},[33,330,132],{"class":50},[33,332,333,335,338],{"class":35,"line":89},[33,334,314],{"class":39},[33,336,337],{"class":69}," \"fallback\"",[33,339,340],{"class":50},";\n",[33,342,343],{"class":35,"line":98},[33,344,345],{"class":50},"  }\n",[33,347,348],{"class":35,"line":107},[33,349,79],{"class":50},[33,351,352],{"class":35,"line":123},[33,353,86],{"emptyLinePlaceholder":85},[33,355,356,358,360,363],{"class":35,"line":135},[33,357,40],{"class":39},[33,359,43],{"class":39},[33,361,362],{"class":46}," a2",[33,364,51],{"class":50},[33,366,367,369],{"class":35,"line":154},[33,368,307],{"class":39},[33,370,95],{"class":50},[33,372,374,376,379,381,383],{"class":35,"line":373},11,[33,375,314],{"class":39},[33,377,378],{"class":39}," await",[33,380,47],{"class":46},[33,382,206],{"class":50},[33,384,385],{"class":150},"\u002F\u002F ✅ waits here, so a failure lands in catch\n",[33,387,389,391,393],{"class":35,"line":388},12,[33,390,326],{"class":50},[33,392,129],{"class":39},[33,394,132],{"class":50},[33,396,398,400,402],{"class":35,"line":397},13,[33,399,314],{"class":39},[33,401,337],{"class":69},[33,403,340],{"class":50},[33,405,407],{"class":35,"line":406},14,[33,408,345],{"class":50},[33,410,412],{"class":35,"line":411},15,[33,413,79],{"class":50},[33,415,417],{"class":35,"line":416},16,[33,418,86],{"emptyLinePlaceholder":85},[33,420,422,424,426,428],{"class":35,"line":421},17,[33,423,251],{"class":39},[33,425,300],{"class":46},[33,427,206],{"class":50},[33,429,430],{"class":150},"\u002F\u002F Error: Server error (catch is skipped)\n",[33,432,434,436,438,440],{"class":35,"line":433},18,[33,435,251],{"class":39},[33,437,362],{"class":46},[33,439,206],{"class":50},[33,441,442],{"class":150},"\u002F\u002F \"fallback\"\n",[444,445,446],"tip",{},[238,447,448],{},[15,449,450,451,454,455,457,458,460,461,245,463,270,465,467],{},"When you return a Promise ",[172,452,453],{},"inside"," a ",[19,456,92],{}," block, use ",[19,459,273],{},". Outside of ",[19,462,92],{},[19,464,269],{},[19,466,273],{}," give the same result.",[261,469],{},[10,471,473,474,477],{"id":472},"trap-2-fetch-succeeds-on-a-404","Trap 2. ",[19,475,476],{},"fetch"," succeeds on a 404",[15,479,480,482,483,486,487,489],{},[19,481,476],{}," only rejects ",[172,484,485],{},"when the network itself fails",". If the server answers with 404 or 500, ",[19,488,476],{}," treats it as success: \"I got a response.\"",[491,492,493,513],"table",{},[494,495,496],"thead",{},[497,498,499,503,508],"tr",{},[500,501,502],"th",{},"Situation",[500,504,505,507],{},[19,506,476],{}," result",[500,509,510],{},[19,511,512],{},"res.ok",[514,515,516,530,544,557],"tbody",{},[497,517,518,522,525],{},[519,520,521],"td",{},"200 OK",[519,523,524],{},"Resolves",[519,526,527],{},[19,528,529],{},"true",[497,531,532,535,539],{},[519,533,534],{},"404 Not Found",[519,536,537],{},[172,538,524],{},[519,540,541],{},[19,542,543],{},"false",[497,545,546,549,553],{},[519,547,548],{},"500 Server Error",[519,550,551],{},[172,552,524],{},[519,554,555],{},[19,556,543],{},[497,558,559,562,569],{},[519,560,561],{},"Offline, bad host, blocked by CORS",[519,563,564,565,568],{},"Rejects (",[19,566,567],{},"TypeError",")",[519,570,571],{},"-",[15,573,574],{},"So you have to check the status yourself.",[24,576,578],{"className":26,"code":577,"language":28,"meta":29,"style":29},"async function getJSON(url) {\n  const res = await fetch(url);\n  if (!res.ok) {\n    throw new Error(`Request failed: ${res.status}`);\n  }\n  return res.json();\n}\n",[19,579,580,598,618,632,659,663,676],{"__ignoreMap":29},[33,581,582,584,586,589,591,595],{"class":35,"line":36},[33,583,40],{"class":39},[33,585,43],{"class":39},[33,587,588],{"class":46}," getJSON",[33,590,66],{"class":50},[33,592,594],{"class":593},"s4XuR","url",[33,596,597],{"class":50},") {\n",[33,599,600,603,607,610,612,615],{"class":35,"line":54},[33,601,602],{"class":39},"  const",[33,604,606],{"class":605},"sj4cs"," res",[33,608,609],{"class":39}," =",[33,611,378],{"class":39},[33,613,614],{"class":46}," fetch",[33,616,617],{"class":50},"(url);\n",[33,619,620,623,626,629],{"class":35,"line":76},[33,621,622],{"class":39},"  if",[33,624,625],{"class":50}," (",[33,627,628],{"class":39},"!",[33,630,631],{"class":50},"res.ok) {\n",[33,633,634,637,639,641,643,646,649,651,654,657],{"class":35,"line":82},[33,635,636],{"class":39},"    throw",[33,638,60],{"class":39},[33,640,63],{"class":46},[33,642,66],{"class":50},[33,644,645],{"class":69},"`Request failed: ${",[33,647,648],{"class":50},"res",[33,650,252],{"class":69},[33,652,653],{"class":50},"status",[33,655,656],{"class":69},"}`",[33,658,73],{"class":50},[33,660,661],{"class":35,"line":89},[33,662,345],{"class":50},[33,664,665,668,671,674],{"class":35,"line":98},[33,666,667],{"class":39},"  return",[33,669,670],{"class":50}," res.",[33,672,673],{"class":46},"json",[33,675,104],{"class":50},[33,677,678],{"class":35,"line":107},[33,679,79],{"class":50},[15,681,682,683,686,687,690],{},"Skip this check and you'll end up reading a 404 page's HTML with ",[19,684,685],{},"res.json()",", getting a confusing ",[19,688,689],{},"SyntaxError"," that hides the real cause (the 404).",[261,692],{},[10,694,696,697,700],{"id":695},"trap-3-promiseall-fails-as-soon-as-one-fails","Trap 3. ",[19,698,699],{},"Promise.all"," fails as soon as one fails",[15,702,703,705,706,709],{},[19,704,699],{},", which you use to send several requests at once, ",[172,707,708],{},"rejects immediately if any one of them fails",". Even if the others succeed, you can't get their results.",[491,711,712,725],{},[494,713,714],{},[497,715,716,719,722],{},[500,717,718],{},"Method",[500,720,721],{},"Settles when",[500,723,724],{},"Result",[514,726,727,742,761,774],{},[497,728,729,733,739],{},[519,730,731],{},[19,732,699],{},[519,734,735,736],{},"All succeed, or ",[172,737,738],{},"immediately when one fails",[519,740,741],{},"Array of values, or the first error",[497,743,744,749,755],{},[519,745,746],{},[19,747,748],{},"Promise.allSettled",[519,750,751,752],{},"Waits ",[172,753,754],{},"until every one is done",[519,756,757,760],{},[19,758,759],{},"{ status, value \u002F reason }"," for each",[497,762,763,768,771],{},[519,764,765],{},[19,766,767],{},"Promise.any",[519,769,770],{},"Any one succeeds",[519,772,773],{},"The first success (error if all fail)",[497,775,776,781,784],{},[519,777,778],{},[19,779,780],{},"Promise.race",[519,782,783],{},"Any one settles (success or failure)",[519,785,786],{},"Whichever settles first",[15,788,789],{},"Press the buttons in the preview below. It sends three requests at once: A (0.6s), B (0.3s, fails), and C (0.9s).",[791,792,793,946,1235],"code-group",{},[24,794,798],{"className":795,"code":796,"language":797,"meta":29,"style":29},"language-html shiki shiki-themes github-light github-dark","\u003Cdiv class=\"buttons\">\n  \u003Cbutton data-run=\"all\">Promise.all\u003C\u002Fbutton>\n  \u003Cbutton data-run=\"allSettled\">Promise.allSettled\u003C\u002Fbutton>\n  \u003Cbutton data-run=\"sequential\">for...of + await (sequential)\u003C\u002Fbutton>\n  \u003Cbutton data-run=\"parallel\">map + Promise.all (parallel)\u003C\u002Fbutton>\n\u003C\u002Fdiv>\n\u003Col id=\"log\">\u003Cli>Press a button\u003C\u002Fli>\u003C\u002Fol>\n","html",[19,799,800,821,844,864,884,904,913],{"__ignoreMap":29},[33,801,802,805,809,812,815,818],{"class":35,"line":36},[33,803,804],{"class":50},"\u003C",[33,806,808],{"class":807},"s9eBZ","div",[33,810,811],{"class":46}," class",[33,813,814],{"class":50},"=",[33,816,817],{"class":69},"\"buttons\"",[33,819,820],{"class":50},">\n",[33,822,823,826,829,832,834,837,840,842],{"class":35,"line":54},[33,824,825],{"class":50},"  \u003C",[33,827,828],{"class":807},"button",[33,830,831],{"class":46}," data-run",[33,833,814],{"class":50},[33,835,836],{"class":69},"\"all\"",[33,838,839],{"class":50},">Promise.all\u003C\u002F",[33,841,828],{"class":807},[33,843,820],{"class":50},[33,845,846,848,850,852,854,857,860,862],{"class":35,"line":76},[33,847,825],{"class":50},[33,849,828],{"class":807},[33,851,831],{"class":46},[33,853,814],{"class":50},[33,855,856],{"class":69},"\"allSettled\"",[33,858,859],{"class":50},">Promise.allSettled\u003C\u002F",[33,861,828],{"class":807},[33,863,820],{"class":50},[33,865,866,868,870,872,874,877,880,882],{"class":35,"line":82},[33,867,825],{"class":50},[33,869,828],{"class":807},[33,871,831],{"class":46},[33,873,814],{"class":50},[33,875,876],{"class":69},"\"sequential\"",[33,878,879],{"class":50},">for...of + await (sequential)\u003C\u002F",[33,881,828],{"class":807},[33,883,820],{"class":50},[33,885,886,888,890,892,894,897,900,902],{"class":35,"line":89},[33,887,825],{"class":50},[33,889,828],{"class":807},[33,891,831],{"class":46},[33,893,814],{"class":50},[33,895,896],{"class":69},"\"parallel\"",[33,898,899],{"class":50},">map + Promise.all (parallel)\u003C\u002F",[33,901,828],{"class":807},[33,903,820],{"class":50},[33,905,906,909,911],{"class":35,"line":98},[33,907,908],{"class":50},"\u003C\u002F",[33,910,808],{"class":807},[33,912,820],{"class":50},[33,914,915,917,920,923,925,928,931,934,937,939,942,944],{"class":35,"line":107},[33,916,804],{"class":50},[33,918,919],{"class":807},"ol",[33,921,922],{"class":46}," id",[33,924,814],{"class":50},[33,926,927],{"class":69},"\"log\"",[33,929,930],{"class":50},">\u003C",[33,932,933],{"class":807},"li",[33,935,936],{"class":50},">Press a button\u003C\u002F",[33,938,933],{"class":807},[33,940,941],{"class":50},">\u003C\u002F",[33,943,919],{"class":807},[33,945,820],{"class":50},[24,947,951],{"className":948,"code":949,"language":950,"meta":29,"style":29},"language-css shiki shiki-themes github-light github-dark",".buttons { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }\nbutton { font: inherit; font-size: 14px; padding: 6px 10px; border: 1px solid #ccc; border-radius: 8px; background: #fff; cursor: pointer; }\n#log { font: 13px\u002F1.7 ui-monospace, monospace; padding-left: 0; list-style: none; margin: 0; min-height: 190px; }\n.ok { color: #15803d; }\n.fail { color: #dc2626; }\n.result { font-weight: 700; color: #b45309; }\n","css",[19,952,953,1009,1103,1176,1193,1209],{"__ignoreMap":29},[33,954,955,958,961,964,967,970,973,976,978,981,983,986,988,991,994,996,999,1001,1004,1006],{"class":35,"line":36},[33,956,957],{"class":46},".buttons",[33,959,960],{"class":50}," { ",[33,962,963],{"class":605},"display",[33,965,966],{"class":50},": ",[33,968,969],{"class":605},"flex",[33,971,972],{"class":50},"; ",[33,974,975],{"class":605},"flex-wrap",[33,977,966],{"class":50},[33,979,980],{"class":605},"wrap",[33,982,972],{"class":50},[33,984,985],{"class":605},"gap",[33,987,966],{"class":50},[33,989,990],{"class":605},"6",[33,992,993],{"class":39},"px",[33,995,972],{"class":50},[33,997,998],{"class":605},"margin-bottom",[33,1000,966],{"class":50},[33,1002,1003],{"class":605},"12",[33,1005,993],{"class":39},[33,1007,1008],{"class":50},"; }\n",[33,1010,1011,1013,1015,1018,1020,1023,1025,1028,1030,1033,1035,1037,1040,1042,1044,1046,1049,1051,1053,1056,1058,1061,1063,1066,1069,1071,1074,1076,1079,1081,1083,1086,1088,1091,1093,1096,1098,1101],{"class":35,"line":54},[33,1012,828],{"class":807},[33,1014,960],{"class":50},[33,1016,1017],{"class":605},"font",[33,1019,966],{"class":50},[33,1021,1022],{"class":605},"inherit",[33,1024,972],{"class":50},[33,1026,1027],{"class":605},"font-size",[33,1029,966],{"class":50},[33,1031,1032],{"class":605},"14",[33,1034,993],{"class":39},[33,1036,972],{"class":50},[33,1038,1039],{"class":605},"padding",[33,1041,966],{"class":50},[33,1043,990],{"class":605},[33,1045,993],{"class":39},[33,1047,1048],{"class":605}," 10",[33,1050,993],{"class":39},[33,1052,972],{"class":50},[33,1054,1055],{"class":605},"border",[33,1057,966],{"class":50},[33,1059,1060],{"class":605},"1",[33,1062,993],{"class":39},[33,1064,1065],{"class":605}," solid",[33,1067,1068],{"class":605}," #ccc",[33,1070,972],{"class":50},[33,1072,1073],{"class":605},"border-radius",[33,1075,966],{"class":50},[33,1077,1078],{"class":605},"8",[33,1080,993],{"class":39},[33,1082,972],{"class":50},[33,1084,1085],{"class":605},"background",[33,1087,966],{"class":50},[33,1089,1090],{"class":605},"#fff",[33,1092,972],{"class":50},[33,1094,1095],{"class":605},"cursor",[33,1097,966],{"class":50},[33,1099,1100],{"class":605},"pointer",[33,1102,1008],{"class":50},[33,1104,1105,1108,1110,1112,1114,1117,1119,1122,1125,1128,1130,1133,1135,1138,1140,1143,1145,1148,1150,1153,1155,1158,1160,1162,1164,1167,1169,1172,1174],{"class":35,"line":76},[33,1106,1107],{"class":46},"#log",[33,1109,960],{"class":50},[33,1111,1017],{"class":605},[33,1113,966],{"class":50},[33,1115,1116],{"class":605},"13",[33,1118,993],{"class":39},[33,1120,1121],{"class":50},"\u002F",[33,1123,1124],{"class":605},"1.7",[33,1126,1127],{"class":605}," ui-monospace",[33,1129,245],{"class":50},[33,1131,1132],{"class":605},"monospace",[33,1134,972],{"class":50},[33,1136,1137],{"class":605},"padding-left",[33,1139,966],{"class":50},[33,1141,1142],{"class":605},"0",[33,1144,972],{"class":50},[33,1146,1147],{"class":605},"list-style",[33,1149,966],{"class":50},[33,1151,1152],{"class":605},"none",[33,1154,972],{"class":50},[33,1156,1157],{"class":605},"margin",[33,1159,966],{"class":50},[33,1161,1142],{"class":605},[33,1163,972],{"class":50},[33,1165,1166],{"class":605},"min-height",[33,1168,966],{"class":50},[33,1170,1171],{"class":605},"190",[33,1173,993],{"class":39},[33,1175,1008],{"class":50},[33,1177,1178,1181,1183,1186,1188,1191],{"class":35,"line":82},[33,1179,1180],{"class":46},".ok",[33,1182,960],{"class":50},[33,1184,1185],{"class":605},"color",[33,1187,966],{"class":50},[33,1189,1190],{"class":605},"#15803d",[33,1192,1008],{"class":50},[33,1194,1195,1198,1200,1202,1204,1207],{"class":35,"line":89},[33,1196,1197],{"class":46},".fail",[33,1199,960],{"class":50},[33,1201,1185],{"class":605},[33,1203,966],{"class":50},[33,1205,1206],{"class":605},"#dc2626",[33,1208,1008],{"class":50},[33,1210,1211,1214,1216,1219,1221,1224,1226,1228,1230,1233],{"class":35,"line":98},[33,1212,1213],{"class":46},".result",[33,1215,960],{"class":50},[33,1217,1218],{"class":605},"font-weight",[33,1220,966],{"class":50},[33,1222,1223],{"class":605},"700",[33,1225,972],{"class":50},[33,1227,1185],{"class":605},[33,1229,966],{"class":50},[33,1231,1232],{"class":605},"#b45309",[33,1234,1008],{"class":50},[24,1236,1238],{"className":26,"code":1237,"language":28,"meta":29,"style":29},"const logEl = document.querySelector(\"#log\");\nlet t0 = 0;\nlet runId = 0;\n\nfunction line(msg, cls = \"\", id) {\n  if (id !== runId) return; \u002F\u002F ignore late logs from a previous run\n  const li = document.createElement(\"li\");\n  li.className = cls;\n  li.textContent = `[${Math.round(performance.now() - t0)}ms] ${msg}`;\n  logEl.append(li);\n}\n\nfunction request(name, ms, fail, id) {\n  line(`${name} request started`, \"\", id);\n  return new Promise((resolve, reject) =>\n    setTimeout(() => {\n      if (fail) {\n        line(`${name} failed ✗`, \"fail\", id);\n        reject(new Error(`${name} failed`));\n      } else {\n        line(`${name} done ✓`, \"ok\", id);\n        resolve(name);\n      }\n    }, ms)\n  );\n}\n\nconst scenarios = {\n  async all(id) {\n    try {\n      const r = await Promise.all([request(\"A\", 600, false, id), request(\"B\", 300, true, id), request(\"C\", 900, false, id)]);\n      line(`Result: ${r}`, \"result\", id);\n    } catch (e) {\n      line(`catch: ${e.message} → no results for A and C (the requests keep going)`, \"result\", id);\n    }\n  },\n  async allSettled(id) {\n    const r = await Promise.allSettled([request(\"A\", 600, false, id), request(\"B\", 300, true, id), request(\"C\", 900, false, id)]);\n    line(`Result: ${r.map((x) => (x.status === \"fulfilled\" ? x.value + \" ok\" : x.reason.message)).join(\", \")}`, \"result\", id);\n  },\n  async sequential(id) {\n    const out = [];\n    for (const name of [\"A\", \"B\", \"C\"]) out.push(await request(name, 400, false, id));\n    line(`Result: ${out} (slow, waits for each one)`, \"result\", id);\n  },\n  async parallel(id) {\n    const out = await Promise.all([\"A\", \"B\", \"C\"].map((name) => request(name, 400, false, id)));\n    line(`Result: ${out} (fast, sent together)`, \"result\", id);\n  },\n};\n\ndocument.querySelectorAll(\"[data-run]\").forEach((btn) =>\n  btn.addEventListener(\"click\", () => {\n    const id = ++runId;\n    logEl.innerHTML = \"\";\n    t0 = performance.now();\n    scenarios[btn.dataset.run](id);\n  })\n);\n",[19,1239,1240,1263,1278,1291,1295,1325,1345,1366,1376,1423,1434,1438,1442,1470,1493,1519,1532,1540,1561,1586,1597,1618,1627,1633,1639,1645,1650,1655,1667,1682,1690,1770,1793,1803,1830,1836,1842,1856,1925,2017,2022,2036,2049,2103,2124,2129,2143,2198,2218,2223,2229,2234,2263,2284,2299,2311,2326,2332,2338],{"__ignoreMap":29},[33,1241,1242,1245,1248,1250,1253,1256,1258,1261],{"class":35,"line":36},[33,1243,1244],{"class":39},"const",[33,1246,1247],{"class":605}," logEl",[33,1249,609],{"class":39},[33,1251,1252],{"class":50}," document.",[33,1254,1255],{"class":46},"querySelector",[33,1257,66],{"class":50},[33,1259,1260],{"class":69},"\"#log\"",[33,1262,73],{"class":50},[33,1264,1265,1268,1271,1273,1276],{"class":35,"line":54},[33,1266,1267],{"class":39},"let",[33,1269,1270],{"class":50}," t0 ",[33,1272,814],{"class":39},[33,1274,1275],{"class":605}," 0",[33,1277,340],{"class":50},[33,1279,1280,1282,1285,1287,1289],{"class":35,"line":76},[33,1281,1267],{"class":39},[33,1283,1284],{"class":50}," runId ",[33,1286,814],{"class":39},[33,1288,1275],{"class":605},[33,1290,340],{"class":50},[33,1292,1293],{"class":35,"line":82},[33,1294,86],{"emptyLinePlaceholder":85},[33,1296,1297,1300,1303,1305,1308,1310,1313,1315,1318,1320,1323],{"class":35,"line":89},[33,1298,1299],{"class":39},"function",[33,1301,1302],{"class":46}," line",[33,1304,66],{"class":50},[33,1306,1307],{"class":593},"msg",[33,1309,245],{"class":50},[33,1311,1312],{"class":593},"cls",[33,1314,609],{"class":39},[33,1316,1317],{"class":69}," \"\"",[33,1319,245],{"class":50},[33,1321,1322],{"class":593},"id",[33,1324,597],{"class":50},[33,1326,1327,1329,1332,1335,1338,1340,1342],{"class":35,"line":98},[33,1328,622],{"class":39},[33,1330,1331],{"class":50}," (id ",[33,1333,1334],{"class":39},"!==",[33,1336,1337],{"class":50}," runId) ",[33,1339,269],{"class":39},[33,1341,972],{"class":50},[33,1343,1344],{"class":150},"\u002F\u002F ignore late logs from a previous run\n",[33,1346,1347,1349,1352,1354,1356,1359,1361,1364],{"class":35,"line":107},[33,1348,602],{"class":39},[33,1350,1351],{"class":605}," li",[33,1353,609],{"class":39},[33,1355,1252],{"class":50},[33,1357,1358],{"class":46},"createElement",[33,1360,66],{"class":50},[33,1362,1363],{"class":69},"\"li\"",[33,1365,73],{"class":50},[33,1367,1368,1371,1373],{"class":35,"line":123},[33,1369,1370],{"class":50},"  li.className ",[33,1372,814],{"class":39},[33,1374,1375],{"class":50}," cls;\n",[33,1377,1378,1381,1383,1386,1389,1391,1394,1396,1399,1401,1404,1407,1409,1412,1414,1417,1419,1421],{"class":35,"line":135},[33,1379,1380],{"class":50},"  li.textContent ",[33,1382,814],{"class":39},[33,1384,1385],{"class":69}," `[${",[33,1387,1388],{"class":50},"Math",[33,1390,252],{"class":69},[33,1392,1393],{"class":46},"round",[33,1395,66],{"class":69},[33,1397,1398],{"class":50},"performance",[33,1400,252],{"class":69},[33,1402,1403],{"class":46},"now",[33,1405,1406],{"class":69},"() ",[33,1408,571],{"class":39},[33,1410,1411],{"class":50}," t0",[33,1413,568],{"class":69},[33,1415,1416],{"class":69},"}ms] ${",[33,1418,1307],{"class":50},[33,1420,656],{"class":69},[33,1422,340],{"class":50},[33,1424,1425,1428,1431],{"class":35,"line":154},[33,1426,1427],{"class":50},"  logEl.",[33,1429,1430],{"class":46},"append",[33,1432,1433],{"class":50},"(li);\n",[33,1435,1436],{"class":35,"line":373},[33,1437,79],{"class":50},[33,1439,1440],{"class":35,"line":388},[33,1441,86],{"emptyLinePlaceholder":85},[33,1443,1444,1446,1449,1451,1454,1456,1459,1461,1464,1466,1468],{"class":35,"line":397},[33,1445,1299],{"class":39},[33,1447,1448],{"class":46}," request",[33,1450,66],{"class":50},[33,1452,1453],{"class":593},"name",[33,1455,245],{"class":50},[33,1457,1458],{"class":593},"ms",[33,1460,245],{"class":50},[33,1462,1463],{"class":593},"fail",[33,1465,245],{"class":50},[33,1467,1322],{"class":593},[33,1469,597],{"class":50},[33,1471,1472,1475,1477,1480,1482,1485,1487,1490],{"class":35,"line":406},[33,1473,1474],{"class":46},"  line",[33,1476,66],{"class":50},[33,1478,1479],{"class":69},"`${",[33,1481,1453],{"class":50},[33,1483,1484],{"class":69},"} request started`",[33,1486,245],{"class":50},[33,1488,1489],{"class":69},"\"\"",[33,1491,1492],{"class":50},", id);\n",[33,1494,1495,1497,1499,1502,1505,1508,1510,1513,1516],{"class":35,"line":411},[33,1496,667],{"class":39},[33,1498,60],{"class":39},[33,1500,1501],{"class":605}," Promise",[33,1503,1504],{"class":50},"((",[33,1506,1507],{"class":593},"resolve",[33,1509,245],{"class":50},[33,1511,1512],{"class":593},"reject",[33,1514,1515],{"class":50},") ",[33,1517,1518],{"class":39},"=>\n",[33,1520,1521,1524,1527,1530],{"class":35,"line":416},[33,1522,1523],{"class":46},"    setTimeout",[33,1525,1526],{"class":50},"(() ",[33,1528,1529],{"class":39},"=>",[33,1531,95],{"class":50},[33,1533,1534,1537],{"class":35,"line":421},[33,1535,1536],{"class":39},"      if",[33,1538,1539],{"class":50}," (fail) {\n",[33,1541,1542,1545,1547,1549,1551,1554,1556,1559],{"class":35,"line":433},[33,1543,1544],{"class":46},"        line",[33,1546,66],{"class":50},[33,1548,1479],{"class":69},[33,1550,1453],{"class":50},[33,1552,1553],{"class":69},"} failed ✗`",[33,1555,245],{"class":50},[33,1557,1558],{"class":69},"\"fail\"",[33,1560,1492],{"class":50},[33,1562,1564,1567,1569,1572,1574,1576,1578,1580,1583],{"class":35,"line":1563},19,[33,1565,1566],{"class":46},"        reject",[33,1568,66],{"class":50},[33,1570,1571],{"class":39},"new",[33,1573,63],{"class":46},[33,1575,66],{"class":50},[33,1577,1479],{"class":69},[33,1579,1453],{"class":50},[33,1581,1582],{"class":69},"} failed`",[33,1584,1585],{"class":50},"));\n",[33,1587,1589,1592,1595],{"class":35,"line":1588},20,[33,1590,1591],{"class":50},"      } ",[33,1593,1594],{"class":39},"else",[33,1596,95],{"class":50},[33,1598,1600,1602,1604,1606,1608,1611,1613,1616],{"class":35,"line":1599},21,[33,1601,1544],{"class":46},[33,1603,66],{"class":50},[33,1605,1479],{"class":69},[33,1607,1453],{"class":50},[33,1609,1610],{"class":69},"} done ✓`",[33,1612,245],{"class":50},[33,1614,1615],{"class":69},"\"ok\"",[33,1617,1492],{"class":50},[33,1619,1621,1624],{"class":35,"line":1620},22,[33,1622,1623],{"class":46},"        resolve",[33,1625,1626],{"class":50},"(name);\n",[33,1628,1630],{"class":35,"line":1629},23,[33,1631,1632],{"class":50},"      }\n",[33,1634,1636],{"class":35,"line":1635},24,[33,1637,1638],{"class":50},"    }, ms)\n",[33,1640,1642],{"class":35,"line":1641},25,[33,1643,1644],{"class":50},"  );\n",[33,1646,1648],{"class":35,"line":1647},26,[33,1649,79],{"class":50},[33,1651,1653],{"class":35,"line":1652},27,[33,1654,86],{"emptyLinePlaceholder":85},[33,1656,1658,1660,1663,1665],{"class":35,"line":1657},28,[33,1659,1244],{"class":39},[33,1661,1662],{"class":605}," scenarios",[33,1664,609],{"class":39},[33,1666,95],{"class":50},[33,1668,1670,1673,1676,1678,1680],{"class":35,"line":1669},29,[33,1671,1672],{"class":39},"  async",[33,1674,1675],{"class":46}," all",[33,1677,66],{"class":50},[33,1679,1322],{"class":593},[33,1681,597],{"class":50},[33,1683,1685,1688],{"class":35,"line":1684},30,[33,1686,1687],{"class":39},"    try",[33,1689,95],{"class":50},[33,1691,1693,1696,1699,1701,1703,1705,1707,1710,1713,1716,1718,1721,1723,1726,1728,1730,1733,1735,1737,1740,1742,1745,1747,1749,1751,1753,1755,1758,1760,1763,1765,1767],{"class":35,"line":1692},31,[33,1694,1695],{"class":39},"      const",[33,1697,1698],{"class":605}," r",[33,1700,609],{"class":39},[33,1702,378],{"class":39},[33,1704,1501],{"class":605},[33,1706,252],{"class":50},[33,1708,1709],{"class":46},"all",[33,1711,1712],{"class":50},"([",[33,1714,1715],{"class":46},"request",[33,1717,66],{"class":50},[33,1719,1720],{"class":69},"\"A\"",[33,1722,245],{"class":50},[33,1724,1725],{"class":605},"600",[33,1727,245],{"class":50},[33,1729,543],{"class":605},[33,1731,1732],{"class":50},", id), ",[33,1734,1715],{"class":46},[33,1736,66],{"class":50},[33,1738,1739],{"class":69},"\"B\"",[33,1741,245],{"class":50},[33,1743,1744],{"class":605},"300",[33,1746,245],{"class":50},[33,1748,529],{"class":605},[33,1750,1732],{"class":50},[33,1752,1715],{"class":46},[33,1754,66],{"class":50},[33,1756,1757],{"class":69},"\"C\"",[33,1759,245],{"class":50},[33,1761,1762],{"class":605},"900",[33,1764,245],{"class":50},[33,1766,543],{"class":605},[33,1768,1769],{"class":50},", id)]);\n",[33,1771,1773,1776,1778,1781,1784,1786,1788,1791],{"class":35,"line":1772},32,[33,1774,1775],{"class":46},"      line",[33,1777,66],{"class":50},[33,1779,1780],{"class":69},"`Result: ${",[33,1782,1783],{"class":50},"r",[33,1785,656],{"class":69},[33,1787,245],{"class":50},[33,1789,1790],{"class":69},"\"result\"",[33,1792,1492],{"class":50},[33,1794,1796,1799,1801],{"class":35,"line":1795},33,[33,1797,1798],{"class":50},"    } ",[33,1800,129],{"class":39},[33,1802,132],{"class":50},[33,1804,1806,1808,1810,1813,1816,1818,1821,1824,1826,1828],{"class":35,"line":1805},34,[33,1807,1775],{"class":46},[33,1809,66],{"class":50},[33,1811,1812],{"class":69},"`catch: ${",[33,1814,1815],{"class":50},"e",[33,1817,252],{"class":69},[33,1819,1820],{"class":50},"message",[33,1822,1823],{"class":69},"} → no results for A and C (the requests keep going)`",[33,1825,245],{"class":50},[33,1827,1790],{"class":69},[33,1829,1492],{"class":50},[33,1831,1833],{"class":35,"line":1832},35,[33,1834,1835],{"class":50},"    }\n",[33,1837,1839],{"class":35,"line":1838},36,[33,1840,1841],{"class":50},"  },\n",[33,1843,1845,1847,1850,1852,1854],{"class":35,"line":1844},37,[33,1846,1672],{"class":39},[33,1848,1849],{"class":46}," allSettled",[33,1851,66],{"class":50},[33,1853,1322],{"class":593},[33,1855,597],{"class":50},[33,1857,1859,1862,1864,1866,1868,1870,1872,1875,1877,1879,1881,1883,1885,1887,1889,1891,1893,1895,1897,1899,1901,1903,1905,1907,1909,1911,1913,1915,1917,1919,1921,1923],{"class":35,"line":1858},38,[33,1860,1861],{"class":39},"    const",[33,1863,1698],{"class":605},[33,1865,609],{"class":39},[33,1867,378],{"class":39},[33,1869,1501],{"class":605},[33,1871,252],{"class":50},[33,1873,1874],{"class":46},"allSettled",[33,1876,1712],{"class":50},[33,1878,1715],{"class":46},[33,1880,66],{"class":50},[33,1882,1720],{"class":69},[33,1884,245],{"class":50},[33,1886,1725],{"class":605},[33,1888,245],{"class":50},[33,1890,543],{"class":605},[33,1892,1732],{"class":50},[33,1894,1715],{"class":46},[33,1896,66],{"class":50},[33,1898,1739],{"class":69},[33,1900,245],{"class":50},[33,1902,1744],{"class":605},[33,1904,245],{"class":50},[33,1906,529],{"class":605},[33,1908,1732],{"class":50},[33,1910,1715],{"class":46},[33,1912,66],{"class":50},[33,1914,1757],{"class":69},[33,1916,245],{"class":50},[33,1918,1762],{"class":605},[33,1920,245],{"class":50},[33,1922,543],{"class":605},[33,1924,1769],{"class":50},[33,1926,1928,1931,1933,1935,1937,1939,1942,1944,1947,1949,1951,1953,1955,1957,1959,1962,1965,1968,1971,1973,1976,1979,1982,1985,1987,1989,1992,1994,1996,1999,2002,2004,2007,2009,2011,2013,2015],{"class":35,"line":1927},39,[33,1929,1930],{"class":46},"    line",[33,1932,66],{"class":50},[33,1934,1780],{"class":69},[33,1936,1783],{"class":50},[33,1938,252],{"class":69},[33,1940,1941],{"class":46},"map",[33,1943,1504],{"class":69},[33,1945,1946],{"class":605},"x",[33,1948,1515],{"class":69},[33,1950,1529],{"class":39},[33,1952,625],{"class":69},[33,1954,1946],{"class":50},[33,1956,252],{"class":69},[33,1958,653],{"class":50},[33,1960,1961],{"class":39}," ===",[33,1963,1964],{"class":69}," \"fulfilled\"",[33,1966,1967],{"class":39}," ?",[33,1969,1970],{"class":50}," x",[33,1972,252],{"class":69},[33,1974,1975],{"class":50},"value",[33,1977,1978],{"class":39}," +",[33,1980,1981],{"class":69}," \" ok\"",[33,1983,1984],{"class":39}," :",[33,1986,1970],{"class":50},[33,1988,252],{"class":69},[33,1990,1991],{"class":50},"reason",[33,1993,252],{"class":69},[33,1995,1820],{"class":50},[33,1997,1998],{"class":69},")).",[33,2000,2001],{"class":46},"join",[33,2003,66],{"class":69},[33,2005,2006],{"class":69},"\", \"",[33,2008,568],{"class":69},[33,2010,656],{"class":69},[33,2012,245],{"class":50},[33,2014,1790],{"class":69},[33,2016,1492],{"class":50},[33,2018,2020],{"class":35,"line":2019},40,[33,2021,1841],{"class":50},[33,2023,2025,2027,2030,2032,2034],{"class":35,"line":2024},41,[33,2026,1672],{"class":39},[33,2028,2029],{"class":46}," sequential",[33,2031,66],{"class":50},[33,2033,1322],{"class":593},[33,2035,597],{"class":50},[33,2037,2039,2041,2044,2046],{"class":35,"line":2038},42,[33,2040,1861],{"class":39},[33,2042,2043],{"class":605}," out",[33,2045,609],{"class":39},[33,2047,2048],{"class":50}," [];\n",[33,2050,2052,2055,2057,2059,2062,2065,2068,2070,2072,2074,2076,2078,2081,2084,2086,2088,2090,2093,2096,2098,2100],{"class":35,"line":2051},43,[33,2053,2054],{"class":39},"    for",[33,2056,625],{"class":50},[33,2058,1244],{"class":39},[33,2060,2061],{"class":605}," name",[33,2063,2064],{"class":39}," of",[33,2066,2067],{"class":50}," [",[33,2069,1720],{"class":69},[33,2071,245],{"class":50},[33,2073,1739],{"class":69},[33,2075,245],{"class":50},[33,2077,1757],{"class":69},[33,2079,2080],{"class":50},"]) out.",[33,2082,2083],{"class":46},"push",[33,2085,66],{"class":50},[33,2087,251],{"class":39},[33,2089,1448],{"class":46},[33,2091,2092],{"class":50},"(name, ",[33,2094,2095],{"class":605},"400",[33,2097,245],{"class":50},[33,2099,543],{"class":605},[33,2101,2102],{"class":50},", id));\n",[33,2104,2106,2108,2110,2112,2115,2118,2120,2122],{"class":35,"line":2105},44,[33,2107,1930],{"class":46},[33,2109,66],{"class":50},[33,2111,1780],{"class":69},[33,2113,2114],{"class":50},"out",[33,2116,2117],{"class":69},"} (slow, waits for each one)`",[33,2119,245],{"class":50},[33,2121,1790],{"class":69},[33,2123,1492],{"class":50},[33,2125,2127],{"class":35,"line":2126},45,[33,2128,1841],{"class":50},[33,2130,2132,2134,2137,2139,2141],{"class":35,"line":2131},46,[33,2133,1672],{"class":39},[33,2135,2136],{"class":46}," parallel",[33,2138,66],{"class":50},[33,2140,1322],{"class":593},[33,2142,597],{"class":50},[33,2144,2146,2148,2150,2152,2154,2156,2158,2160,2162,2164,2166,2168,2170,2172,2175,2177,2179,2181,2183,2185,2187,2189,2191,2193,2195],{"class":35,"line":2145},47,[33,2147,1861],{"class":39},[33,2149,2043],{"class":605},[33,2151,609],{"class":39},[33,2153,378],{"class":39},[33,2155,1501],{"class":605},[33,2157,252],{"class":50},[33,2159,1709],{"class":46},[33,2161,1712],{"class":50},[33,2163,1720],{"class":69},[33,2165,245],{"class":50},[33,2167,1739],{"class":69},[33,2169,245],{"class":50},[33,2171,1757],{"class":69},[33,2173,2174],{"class":50},"].",[33,2176,1941],{"class":46},[33,2178,1504],{"class":50},[33,2180,1453],{"class":593},[33,2182,1515],{"class":50},[33,2184,1529],{"class":39},[33,2186,1448],{"class":46},[33,2188,2092],{"class":50},[33,2190,2095],{"class":605},[33,2192,245],{"class":50},[33,2194,543],{"class":605},[33,2196,2197],{"class":50},", id)));\n",[33,2199,2201,2203,2205,2207,2209,2212,2214,2216],{"class":35,"line":2200},48,[33,2202,1930],{"class":46},[33,2204,66],{"class":50},[33,2206,1780],{"class":69},[33,2208,2114],{"class":50},[33,2210,2211],{"class":69},"} (fast, sent together)`",[33,2213,245],{"class":50},[33,2215,1790],{"class":69},[33,2217,1492],{"class":50},[33,2219,2221],{"class":35,"line":2220},49,[33,2222,1841],{"class":50},[33,2224,2226],{"class":35,"line":2225},50,[33,2227,2228],{"class":50},"};\n",[33,2230,2232],{"class":35,"line":2231},51,[33,2233,86],{"emptyLinePlaceholder":85},[33,2235,2237,2240,2243,2245,2248,2251,2254,2256,2259,2261],{"class":35,"line":2236},52,[33,2238,2239],{"class":50},"document.",[33,2241,2242],{"class":46},"querySelectorAll",[33,2244,66],{"class":50},[33,2246,2247],{"class":69},"\"[data-run]\"",[33,2249,2250],{"class":50},").",[33,2252,2253],{"class":46},"forEach",[33,2255,1504],{"class":50},[33,2257,2258],{"class":593},"btn",[33,2260,1515],{"class":50},[33,2262,1518],{"class":39},[33,2264,2266,2269,2272,2274,2277,2280,2282],{"class":35,"line":2265},53,[33,2267,2268],{"class":50},"  btn.",[33,2270,2271],{"class":46},"addEventListener",[33,2273,66],{"class":50},[33,2275,2276],{"class":69},"\"click\"",[33,2278,2279],{"class":50},", () ",[33,2281,1529],{"class":39},[33,2283,95],{"class":50},[33,2285,2287,2289,2291,2293,2296],{"class":35,"line":2286},54,[33,2288,1861],{"class":39},[33,2290,922],{"class":605},[33,2292,609],{"class":39},[33,2294,2295],{"class":39}," ++",[33,2297,2298],{"class":50},"runId;\n",[33,2300,2302,2305,2307,2309],{"class":35,"line":2301},55,[33,2303,2304],{"class":50},"    logEl.innerHTML ",[33,2306,814],{"class":39},[33,2308,1317],{"class":69},[33,2310,340],{"class":50},[33,2312,2314,2317,2319,2322,2324],{"class":35,"line":2313},56,[33,2315,2316],{"class":50},"    t0 ",[33,2318,814],{"class":39},[33,2320,2321],{"class":50}," performance.",[33,2323,1403],{"class":46},[33,2325,104],{"class":50},[33,2327,2329],{"class":35,"line":2328},57,[33,2330,2331],{"class":50},"    scenarios[btn.dataset.run](id);\n",[33,2333,2335],{"class":35,"line":2334},58,[33,2336,2337],{"class":50},"  })\n",[33,2339,2341],{"class":35,"line":2340},59,[33,2342,73],{"class":50},[15,2344,2345,2346,2348,2349,2351,2352,253,2355,2357],{},"Press ",[19,2347,699],{}," and it jumps to ",[19,2350,129],{}," at 0.3s when B fails, but ",[172,2353,2354],{},"A and C keep running and finish afterward.",[19,2356,699],{}," doesn't cancel anything; it just throws the results away.",[2359,2360,2362],"h3",{"id":2361},"which-one-should-you-use","Which one should you use?",[491,2364,2365,2374],{},[494,2366,2367],{},[497,2368,2369,2371],{},[500,2370,502],{},[500,2372,2373],{},"Use",[514,2375,2376,2385,2394,2403],{},[497,2377,2378,2381],{},[519,2379,2380],{},"You need all of it (product info + price + stock)",[519,2382,2383],{},[19,2384,699],{},[497,2386,2387,2390],{},[519,2388,2389],{},"Show what you can even if some fail (several dashboard widgets)",[519,2391,2392],{},[19,2393,748],{},[497,2395,2396,2399],{},[519,2397,2398],{},"Use whichever of several servers answers first",[519,2400,2401],{},[19,2402,767],{},[497,2404,2405,2408],{},[519,2406,2407],{},"Race against a timeout",[519,2409,2410,2412,2413,2416],{},[19,2411,780],{}," (these days ",[19,2414,2415],{},"AbortSignal.timeout"," is better)",[261,2418],{},[10,2420,2422,2423,2425],{"id":2421},"trap-4-await-inside-loops","Trap 4. ",[19,2424,251],{}," inside loops",[2359,2427,2429,2432,2433,2435],{"id":2428},"forof-await-waits-for-each-one",[19,2430,2431],{},"for...of"," + ",[19,2434,251],{}," waits for each one",[24,2437,2439],{"className":26,"code":2438,"language":28,"meta":29,"style":29},"\u002F\u002F If each request takes 0.2s, this takes 0.6s total\nfor (const id of [1, 2, 3]) {\n  users.push(await getUser(id));\n}\n\n\u002F\u002F Sent together, it takes 0.2s total\nconst users = await Promise.all([1, 2, 3].map(getUser));\n",[19,2440,2441,2446,2476,2493,2497,2501,2506],{"__ignoreMap":29},[33,2442,2443],{"class":35,"line":36},[33,2444,2445],{"class":150},"\u002F\u002F If each request takes 0.2s, this takes 0.6s total\n",[33,2447,2448,2451,2453,2455,2457,2459,2461,2463,2465,2468,2470,2473],{"class":35,"line":54},[33,2449,2450],{"class":39},"for",[33,2452,625],{"class":50},[33,2454,1244],{"class":39},[33,2456,922],{"class":605},[33,2458,2064],{"class":39},[33,2460,2067],{"class":50},[33,2462,1060],{"class":605},[33,2464,245],{"class":50},[33,2466,2467],{"class":605},"2",[33,2469,245],{"class":50},[33,2471,2472],{"class":605},"3",[33,2474,2475],{"class":50},"]) {\n",[33,2477,2478,2481,2483,2485,2487,2490],{"class":35,"line":76},[33,2479,2480],{"class":50},"  users.",[33,2482,2083],{"class":46},[33,2484,66],{"class":50},[33,2486,251],{"class":39},[33,2488,2489],{"class":46}," getUser",[33,2491,2492],{"class":50},"(id));\n",[33,2494,2495],{"class":35,"line":82},[33,2496,79],{"class":50},[33,2498,2499],{"class":35,"line":89},[33,2500,86],{"emptyLinePlaceholder":85},[33,2502,2503],{"class":35,"line":98},[33,2504,2505],{"class":150},"\u002F\u002F Sent together, it takes 0.2s total\n",[33,2507,2508,2510,2513,2515,2517,2519,2521,2523,2525,2527,2529,2531,2533,2535,2537,2539],{"class":35,"line":107},[33,2509,1244],{"class":39},[33,2511,2512],{"class":605}," users",[33,2514,609],{"class":39},[33,2516,378],{"class":39},[33,2518,1501],{"class":605},[33,2520,252],{"class":50},[33,2522,1709],{"class":46},[33,2524,1712],{"class":50},[33,2526,1060],{"class":605},[33,2528,245],{"class":50},[33,2530,2467],{"class":605},[33,2532,245],{"class":50},[33,2534,2472],{"class":605},[33,2536,2174],{"class":50},[33,2538,1941],{"class":46},[33,2540,2541],{"class":50},"(getUser));\n",[15,2543,2544,2545,2432,2547,2549,2550,2553],{},"If the requests don't depend on each other, sending them together with ",[19,2546,1941],{},[19,2548,699],{}," is much faster. Use the \"sequential\" and \"parallel\" buttons in the demo above to see the difference. On the other hand, ",[172,2551,2552],{},"if each request needs the previous one's result, or you shouldn't hit the server all at once",", sequential is the right call.",[2359,2555,2557,2432,2559,2561],{"id":2556},"foreach-async-doesnt-wait",[19,2558,2253],{},[19,2560,40],{}," doesn't wait",[24,2563,2565],{"className":26,"code":2564,"language":28,"meta":29,"style":29},"const result = [];\n[1, 2, 3].forEach(async (id) => {\n  result.push(await getUser(id));\n});\nconsole.log(result); \u002F\u002F [] ← moved on immediately without waiting\n",[19,2566,2567,2577,2610,2625,2630],{"__ignoreMap":29},[33,2568,2569,2571,2573,2575],{"class":35,"line":36},[33,2570,1244],{"class":39},[33,2572,507],{"class":605},[33,2574,609],{"class":39},[33,2576,2048],{"class":50},[33,2578,2579,2582,2584,2586,2588,2590,2592,2594,2596,2598,2600,2602,2604,2606,2608],{"class":35,"line":54},[33,2580,2581],{"class":50},"[",[33,2583,1060],{"class":605},[33,2585,245],{"class":50},[33,2587,2467],{"class":605},[33,2589,245],{"class":50},[33,2591,2472],{"class":605},[33,2593,2174],{"class":50},[33,2595,2253],{"class":46},[33,2597,66],{"class":50},[33,2599,40],{"class":39},[33,2601,625],{"class":50},[33,2603,1322],{"class":593},[33,2605,1515],{"class":50},[33,2607,1529],{"class":39},[33,2609,95],{"class":50},[33,2611,2612,2615,2617,2619,2621,2623],{"class":35,"line":76},[33,2613,2614],{"class":50},"  result.",[33,2616,2083],{"class":46},[33,2618,66],{"class":50},[33,2620,251],{"class":39},[33,2622,2489],{"class":46},[33,2624,2492],{"class":50},[33,2626,2627],{"class":35,"line":82},[33,2628,2629],{"class":50},"});\n",[33,2631,2632,2635,2637,2640],{"class":35,"line":89},[33,2633,2634],{"class":50},"console.",[33,2636,113],{"class":46},[33,2638,2639],{"class":50},"(result); ",[33,2641,2642],{"class":150},"\u002F\u002F [] ← moved on immediately without waiting\n",[15,2644,2645,2647,2648,2650],{},[19,2646,2253],{}," ignores the Promise its callback returns. The loop ends immediately, and if something throws, the surrounding ",[19,2649,21],{}," can't catch it.",[2652,2653,2654],"warning",{},[238,2655,2656],{},[15,2657,2658,2659,2661,2662,2664,2665,2667,2668,2432,2670,252],{},"Don't use ",[19,2660,251],{}," inside ",[19,2663,2253],{},". If you need to wait in order, use ",[19,2666,2431],{},"; if they can run together, use ",[19,2669,1941],{},[19,2671,699],{},[261,2673],{},[10,2675,2677],{"id":2676},"trap-5-requests-that-never-finish-timeouts-and-cancellation","Trap 5. Requests that never finish: timeouts and cancellation",[15,2679,2680,2682,2683,252],{},[19,2681,476],{}," has no default timeout. If the server never responds, the loading spinner spins forever. Set a limit with ",[19,2684,2685],{},"AbortSignal.timeout()",[24,2687,2689],{"className":26,"code":2688,"language":28,"meta":29,"style":29},"try {\n  const res = await fetch(\"\u002Fapi\u002Freport\", { signal: AbortSignal.timeout(5000) });\n} catch (e) {\n  if (e.name === \"TimeoutError\") {\n    console.log(\"No response within 5 seconds\");\n  }\n}\n",[19,2690,2691,2697,2728,2736,2751,2765,2769],{"__ignoreMap":29},[33,2692,2693,2695],{"class":35,"line":36},[33,2694,92],{"class":39},[33,2696,95],{"class":50},[33,2698,2699,2701,2703,2705,2707,2709,2711,2714,2717,2720,2722,2725],{"class":35,"line":54},[33,2700,602],{"class":39},[33,2702,606],{"class":605},[33,2704,609],{"class":39},[33,2706,378],{"class":39},[33,2708,614],{"class":46},[33,2710,66],{"class":50},[33,2712,2713],{"class":69},"\"\u002Fapi\u002Freport\"",[33,2715,2716],{"class":50},", { signal: AbortSignal.",[33,2718,2719],{"class":46},"timeout",[33,2721,66],{"class":50},[33,2723,2724],{"class":605},"5000",[33,2726,2727],{"class":50},") });\n",[33,2729,2730,2732,2734],{"class":35,"line":76},[33,2731,126],{"class":50},[33,2733,129],{"class":39},[33,2735,132],{"class":50},[33,2737,2738,2740,2743,2746,2749],{"class":35,"line":82},[33,2739,622],{"class":39},[33,2741,2742],{"class":50}," (e.name ",[33,2744,2745],{"class":39},"===",[33,2747,2748],{"class":69}," \"TimeoutError\"",[33,2750,597],{"class":50},[33,2752,2753,2756,2758,2760,2763],{"class":35,"line":89},[33,2754,2755],{"class":50},"    console.",[33,2757,113],{"class":46},[33,2759,66],{"class":50},[33,2761,2762],{"class":69},"\"No response within 5 seconds\"",[33,2764,73],{"class":50},[33,2766,2767],{"class":35,"line":98},[33,2768,345],{"class":50},[33,2770,2771],{"class":35,"line":107},[33,2772,79],{"class":50},[15,2774,2775,2776,2779,2780,252],{},"When ",[172,2777,2778],{},"a previous request is no longer needed"," because the user left the page or changed the search term, cancel it yourself with ",[19,2781,2782],{},"AbortController",[24,2784,2786],{"className":26,"code":2785,"language":28,"meta":29,"style":29},"let controller;\n\nasync function search(keyword) {\n  controller?.abort(); \u002F\u002F cancel the previous search request\n  controller = new AbortController();\n  try {\n    const res = await fetch(`\u002Fapi\u002Fsearch?q=${keyword}`, { signal: controller.signal });\n    return await res.json();\n  } catch (e) {\n    if (e.name === \"AbortError\") return; \u002F\u002F a deliberate cancel isn't an error\n    throw e;\n  }\n}\n",[19,2787,2788,2795,2799,2815,2828,2842,2848,2872,2884,2892,2913,2920,2924],{"__ignoreMap":29},[33,2789,2790,2792],{"class":35,"line":36},[33,2791,1267],{"class":39},[33,2793,2794],{"class":50}," controller;\n",[33,2796,2797],{"class":35,"line":54},[33,2798,86],{"emptyLinePlaceholder":85},[33,2800,2801,2803,2805,2808,2810,2813],{"class":35,"line":76},[33,2802,40],{"class":39},[33,2804,43],{"class":39},[33,2806,2807],{"class":46}," search",[33,2809,66],{"class":50},[33,2811,2812],{"class":593},"keyword",[33,2814,597],{"class":50},[33,2816,2817,2820,2823,2825],{"class":35,"line":82},[33,2818,2819],{"class":50},"  controller?.",[33,2821,2822],{"class":46},"abort",[33,2824,206],{"class":50},[33,2826,2827],{"class":150},"\u002F\u002F cancel the previous search request\n",[33,2829,2830,2833,2835,2837,2840],{"class":35,"line":89},[33,2831,2832],{"class":50},"  controller ",[33,2834,814],{"class":39},[33,2836,60],{"class":39},[33,2838,2839],{"class":46}," AbortController",[33,2841,104],{"class":50},[33,2843,2844,2846],{"class":35,"line":98},[33,2845,307],{"class":39},[33,2847,95],{"class":50},[33,2849,2850,2852,2854,2856,2858,2860,2862,2865,2867,2869],{"class":35,"line":107},[33,2851,1861],{"class":39},[33,2853,606],{"class":605},[33,2855,609],{"class":39},[33,2857,378],{"class":39},[33,2859,614],{"class":46},[33,2861,66],{"class":50},[33,2863,2864],{"class":69},"`\u002Fapi\u002Fsearch?q=${",[33,2866,2812],{"class":50},[33,2868,656],{"class":69},[33,2870,2871],{"class":50},", { signal: controller.signal });\n",[33,2873,2874,2876,2878,2880,2882],{"class":35,"line":123},[33,2875,314],{"class":39},[33,2877,378],{"class":39},[33,2879,670],{"class":50},[33,2881,673],{"class":46},[33,2883,104],{"class":50},[33,2885,2886,2888,2890],{"class":35,"line":135},[33,2887,326],{"class":50},[33,2889,129],{"class":39},[33,2891,132],{"class":50},[33,2893,2894,2897,2899,2901,2904,2906,2908,2910],{"class":35,"line":154},[33,2895,2896],{"class":39},"    if",[33,2898,2742],{"class":50},[33,2900,2745],{"class":39},[33,2902,2903],{"class":69}," \"AbortError\"",[33,2905,1515],{"class":50},[33,2907,269],{"class":39},[33,2909,972],{"class":50},[33,2911,2912],{"class":150},"\u002F\u002F a deliberate cancel isn't an error\n",[33,2914,2915,2917],{"class":35,"line":373},[33,2916,636],{"class":39},[33,2918,2919],{"class":50}," e;\n",[33,2921,2922],{"class":35,"line":388},[33,2923,345],{"class":50},[33,2925,2926],{"class":35,"line":397},[33,2927,79],{"class":50},[15,2929,2930],{},"This also prevents the bug where a late response from an older search overwrites the latest results.",[261,2932],{},[10,2934,2936],{"id":2935},"where-and-how-to-handle-errors","Where and how to handle errors",[2359,2938,2940,2941],{"id":2939},"rethrow-without-losing-the-cause-cause","Rethrow without losing the cause: ",[19,2942,2943],{},"cause",[15,2945,2946,2947,2949],{},"When you catch a low-level error and turn it into a clearer one, put the original in ",[19,2948,2943],{}," so you can trace it when debugging.",[24,2951,2953],{"className":26,"code":2952,"language":28,"meta":29,"style":29},"try {\n  JSON.parse(text);\n} catch (err) {\n  throw new Error(\"Couldn't read the config file\", { cause: err });\n}\n\u002F\u002F e.message → \"Couldn't read the config file\"\n\u002F\u002F e.cause   → SyntaxError: ...\n",[19,2954,2955,2961,2974,2983,2999,3003,3008],{"__ignoreMap":29},[33,2956,2957,2959],{"class":35,"line":36},[33,2958,92],{"class":39},[33,2960,95],{"class":50},[33,2962,2963,2966,2968,2971],{"class":35,"line":54},[33,2964,2965],{"class":605},"  JSON",[33,2967,252],{"class":50},[33,2969,2970],{"class":46},"parse",[33,2972,2973],{"class":50},"(text);\n",[33,2975,2976,2978,2980],{"class":35,"line":76},[33,2977,126],{"class":50},[33,2979,129],{"class":39},[33,2981,2982],{"class":50}," (err) {\n",[33,2984,2985,2987,2989,2991,2993,2996],{"class":35,"line":82},[33,2986,57],{"class":39},[33,2988,60],{"class":39},[33,2990,63],{"class":46},[33,2992,66],{"class":50},[33,2994,2995],{"class":69},"\"Couldn't read the config file\"",[33,2997,2998],{"class":50},", { cause: err });\n",[33,3000,3001],{"class":35,"line":89},[33,3002,79],{"class":50},[33,3004,3005],{"class":35,"line":98},[33,3006,3007],{"class":150},"\u002F\u002F e.message → \"Couldn't read the config file\"\n",[33,3009,3010],{"class":35,"line":107},[33,3011,3012],{"class":150},"\u002F\u002F e.cause   → SyntaxError: ...\n",[2359,3014,3016],{"id":3015},"dont-swallow-errors","Don't swallow errors",[24,3018,3020],{"className":26,"code":3019,"language":28,"meta":29,"style":29},"\u002F\u002F ❌ Catch an error and do nothing, and the fact that it failed disappears\ntry {\n  await save();\n} catch (e) {}\n",[19,3021,3022,3027,3033,3042],{"__ignoreMap":29},[33,3023,3024],{"class":35,"line":36},[33,3025,3026],{"class":150},"\u002F\u002F ❌ Catch an error and do nothing, and the fact that it failed disappears\n",[33,3028,3029,3031],{"class":35,"line":54},[33,3030,92],{"class":39},[33,3032,95],{"class":50},[33,3034,3035,3037,3040],{"class":35,"line":76},[33,3036,201],{"class":39},[33,3038,3039],{"class":46}," save",[33,3041,104],{"class":50},[33,3043,3044,3046,3048],{"class":35,"line":82},[33,3045,126],{"class":50},[33,3047,129],{"class":39},[33,3049,3050],{"class":50}," (e) {}\n",[15,3052,3053,3054,3056,3057,3060],{},"A ",[19,3055,129],{}," should do one of three things: ",[172,3058,3059],{},"tell the user, recover with a fallback, or rethrow."," Where you can't handle an error, don't catch it. Let it bubble up to one place that can (the UI layer, the API client layer) and deal with it there.",[2359,3062,3064,3065],{"id":3063},"the-last-safety-net-unhandledrejection","The last safety net: ",[19,3066,3067],{},"unhandledrejection",[15,3069,3070],{},"Promise errors nobody caught can be received through a global event. Use it to send them to an error monitoring tool.",[24,3072,3074],{"className":26,"code":3073,"language":28,"meta":29,"style":29},"window.addEventListener(\"unhandledrejection\", (event) => {\n  sendToMonitoring(event.reason); \u002F\u002F send to a monitoring service (your own function)\n});\n",[19,3075,3076,3100,3111],{"__ignoreMap":29},[33,3077,3078,3081,3083,3085,3088,3091,3094,3096,3098],{"class":35,"line":36},[33,3079,3080],{"class":50},"window.",[33,3082,2271],{"class":46},[33,3084,66],{"class":50},[33,3086,3087],{"class":69},"\"unhandledrejection\"",[33,3089,3090],{"class":50},", (",[33,3092,3093],{"class":593},"event",[33,3095,1515],{"class":50},[33,3097,1529],{"class":39},[33,3099,95],{"class":50},[33,3101,3102,3105,3108],{"class":35,"line":54},[33,3103,3104],{"class":46},"  sendToMonitoring",[33,3106,3107],{"class":50},"(event.reason); ",[33,3109,3110],{"class":150},"\u002F\u002F send to a monitoring service (your own function)\n",[33,3112,3113],{"class":35,"line":76},[33,3114,2629],{"class":50},[15,3116,3117,3118,3121,3122,3125],{},"In Node.js it's ",[19,3119,3120],{},"process.on(\"unhandledRejection\", ...)",". This is strictly for ",[172,3123,3124],{},"recording errors you missed",", not a replacement for handling them.",[261,3127],{},[10,3129,3131],{"id":3130},"summary-why-this-is-worth-knowing","Summary: why this is worth knowing",[491,3133,3134,3144],{},[494,3135,3136],{},[497,3137,3138,3141],{},[500,3139,3140],{},"Trap",[500,3142,3143],{},"Correct handling",[514,3145,3146,3158,3172,3184,3196,3212,3227,3237,3247],{},[497,3147,3148,3153],{},[519,3149,3150,3152],{},[19,3151,21],{}," misses async errors",[519,3154,3155,3156],{},"Add ",[19,3157,251],{},[497,3159,3160,3167],{},[519,3161,3162,2661,3165],{},[19,3163,3164],{},"return promise",[19,3166,92],{},[519,3168,3169],{},[19,3170,3171],{},"return await promise",[497,3173,3174,3179],{},[519,3175,3176,3178],{},[19,3177,476],{}," resolves on 404\u002F500",[519,3180,3181],{},[19,3182,3183],{},"if (!res.ok) throw ...",[497,3185,3186,3191],{},[519,3187,3188,3190],{},[19,3189,699],{}," loses everything when one fails",[519,3192,3193,3195],{},[19,3194,1874],{}," if partial failure is OK",[497,3197,3198,3205],{},[519,3199,3200,2432,3202,3204],{},[19,3201,2431],{},[19,3203,251],{}," is slow",[519,3206,3207,2432,3209,3211],{},[19,3208,1941],{},[19,3210,699],{}," for independent requests",[497,3213,3214,3220],{},[519,3215,3216,2432,3218,2561],{},[19,3217,2253],{},[19,3219,40],{},[519,3221,3222,3224,3225],{},[19,3223,2431],{}," or ",[19,3226,699],{},[497,3228,3229,3232],{},[519,3230,3231],{},"Requests that never finish",[519,3233,3234],{},[19,3235,3236],{},"AbortSignal.timeout(ms)",[497,3238,3239,3242],{},[519,3240,3241],{},"Requests you no longer need",[519,3243,3244,3245],{},"Cancel with ",[19,3246,2782],{},[497,3248,3249,3252],{},[519,3250,3251],{},"Losing the cause when converting errors",[519,3253,3254],{},[19,3255,3256],{},"new Error(msg, { cause })",[15,3258,3259,3260,3263,3264,3266,3267,3269,3270,3272,3273,3275,3276],{},"Unlike synchronous errors, async errors ",[172,3261,3262],{},"disappear quietly",". Small differences, one ",[19,3265,251],{},", one ",[19,3268,512],{}," line, ",[19,3271,2431],{}," instead of ",[19,3274,2253],{},", separate \"an error happened and nobody knew\" from \"the failure was reported and recovered from.\" When you write async code, ask each time: ",[172,3277,3278],{},"\"If this Promise fails, where does the error go?\"",[3280,3281,3282],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":29,"searchDepth":54,"depth":54,"links":3284},[3285,3286,3288,3290,3294,3301,3302,3309],{"id":12,"depth":54,"text":13},{"id":265,"depth":54,"text":3287},"Trap 1. return and return await are different",{"id":472,"depth":54,"text":3289},"Trap 2. fetch succeeds on a 404",{"id":695,"depth":54,"text":3291,"children":3292},"Trap 3. Promise.all fails as soon as one fails",[3293],{"id":2361,"depth":76,"text":2362},{"id":2421,"depth":54,"text":3295,"children":3296},"Trap 4. await inside loops",[3297,3299],{"id":2428,"depth":76,"text":3298},"for...of + await waits for each one",{"id":2556,"depth":76,"text":3300},"forEach + async doesn't wait",{"id":2676,"depth":54,"text":2677},{"id":2935,"depth":54,"text":2936,"children":3303},[3304,3306,3307],{"id":2939,"depth":76,"text":3305},"Rethrow without losing the cause: cause",{"id":3015,"depth":76,"text":3016},{"id":3063,"depth":76,"text":3308},"The last safety net: unhandledrejection",{"id":3130,"depth":54,"text":3131},"You wrapped it in try\u002Fcatch and the error still escapes; the server returned 404 and fetch says it succeeded. The traps of async error handling: try\u002Fcatch without await, return vs return await, fetch's res.ok, Promise.all vs allSettled, await in loops, and timeouts and cancellation, with a runnable demo.","md",{"date":3313,"field":3314,"tags":3315},"2026.10.08","frontend",[3316],"javascript","\u002Fen\u002Fjavascript-async-error-handling",{"title":5,"description":3310},{"loc":3317},"en\u002Fjavascript-async-error-handling","FxJrQTyTreK_0Lbf95FosXUTTQQV7dMmKXoDWjiqfWM",1791482016517]