[{"data":1,"prerenderedAt":1237},["ShallowReactive",2],{"blog-\u002Fblog\u002Fjavascript-promises-async-await":3},{"id":4,"title":5,"body":6,"description":1223,"difficulty":1224,"extension":1225,"framework":1226,"frameworkSlug":1227,"meta":1228,"navigation":693,"order":65,"path":1229,"qaPath":1230,"seo":1231,"stem":1232,"subtopic":1233,"topic":1234,"topicSlug":398,"updated":1235,"__hash__":1236},"blog\u002Fblog\u002Fjavascript-promises-async-await.md","JavaScript Promises & Async\u002FAwait — The Complete Guide",{"type":7,"value":8,"toc":1211},"minimark",[9,14,23,27,30,52,173,211,215,225,369,391,394,417,481,496,500,520,602,629,633,648,736,743,768,772,844,866,894,898,911,946,968,1052,1056,1155,1168,1172,1207],[10,11,13],"h2",{"id":12},"a-complete-guide-to-promises-and-asyncawait","A complete guide to promises and async\u002Fawait",[15,16,17,18,22],"p",{},"Asynchronous code is unavoidable in JavaScript — anything involving the network, the\nfile system, or timers happens later, not now. Promises are the language's standard\nabstraction for \"a value you'll have eventually,\" and ",[19,20,21],"code",{},"async\u002Fawait"," is the syntax that\nmakes them read like ordinary code. This guide covers what promises are, how chaining\nand error handling work, the combinator methods, and the patterns and traps that\nseparate confident developers from confused ones.",[10,24,26],{"id":25},"what-a-promise-is","What a promise is",[15,28,29],{},"A promise is an object representing the eventual result of an async operation. It lives\nin one of three states:",[31,32,33,40,46],"ul",{},[34,35,36,39],"li",{},[19,37,38],{},"pending"," — not yet settled.",[34,41,42,45],{},[19,43,44],{},"fulfilled"," — completed successfully, holds a value.",[34,47,48,51],{},[19,49,50],{},"rejected"," — failed, holds a reason.",[53,54,59],"pre",{"className":55,"code":56,"language":57,"meta":58,"style":58},"language-js shiki shiki-themes github-light github-dark","const p = new Promise((resolve, reject) => {\n  setTimeout(() => resolve('done'), 100)\n})\np.then(value => console.log(value)) \u002F\u002F 'done'\n","js","",[19,60,61,106,137,143],{"__ignoreMap":58},[62,63,66,70,74,77,80,83,87,91,94,97,100,103],"span",{"class":64,"line":65},"line",1,[62,67,69],{"class":68},"szBVR","const",[62,71,73],{"class":72},"sj4cs"," p",[62,75,76],{"class":68}," =",[62,78,79],{"class":68}," new",[62,81,82],{"class":72}," Promise",[62,84,86],{"class":85},"sVt8B","((",[62,88,90],{"class":89},"s4XuR","resolve",[62,92,93],{"class":85},", ",[62,95,96],{"class":89},"reject",[62,98,99],{"class":85},") ",[62,101,102],{"class":68},"=>",[62,104,105],{"class":85}," {\n",[62,107,109,113,116,118,121,124,128,131,134],{"class":64,"line":108},2,[62,110,112],{"class":111},"sScJk","  setTimeout",[62,114,115],{"class":85},"(() ",[62,117,102],{"class":68},[62,119,120],{"class":111}," resolve",[62,122,123],{"class":85},"(",[62,125,127],{"class":126},"sZZnC","'done'",[62,129,130],{"class":85},"), ",[62,132,133],{"class":72},"100",[62,135,136],{"class":85},")\n",[62,138,140],{"class":64,"line":139},3,[62,141,142],{"class":85},"})\n",[62,144,146,149,152,154,157,160,163,166,169],{"class":64,"line":145},4,[62,147,148],{"class":85},"p.",[62,150,151],{"class":111},"then",[62,153,123],{"class":85},[62,155,156],{"class":89},"value",[62,158,159],{"class":68}," =>",[62,161,162],{"class":85}," console.",[62,164,165],{"class":111},"log",[62,167,168],{"class":85},"(value)) ",[62,170,172],{"class":171},"sJ8bj","\u002F\u002F 'done'\n",[15,174,175,176,180,181,183,184,186,187,183,190,193,194,197,198,201,202,205,206,210],{},"Two guarantees make promises composable. A promise settles ",[177,178,179],"strong",{},"once"," — after that its\nstate and value are immutable, so calling ",[19,182,90],{},"\u002F",[19,185,96],{}," again does nothing. And\n",[19,188,189],{},".then",[19,191,192],{},".catch"," callbacks always run ",[177,195,196],{},"asynchronously as microtasks",", never\nsynchronously — even for an already-resolved promise. One subtlety: the ",[177,199,200],{},"executor","\nfunction you pass to ",[19,203,204],{},"new Promise"," runs ",[207,208,209],"em",{},"synchronously, immediately","; only the\ncallbacks are deferred.",[10,212,214],{"id":213},"chaining","Chaining",[15,216,217,218,220,221,224],{},"Each ",[19,219,189],{}," returns a ",[177,222,223],{},"new promise"," that resolves to whatever its callback returns.\nThat's what lets you chain steps into a linear sequence instead of nesting callbacks.",[53,226,228],{"className":55,"code":227,"language":57,"meta":58,"style":58},"fetch('\u002Fapi\u002Fuser')\n  .then(res => res.json())              \u002F\u002F returns parsed body\n  .then(user => fetch(`\u002Fposts\u002F${user.id}`))\n  .then(res => res.json())\n  .then(posts => console.log(posts))\n  .catch(err => console.error(err))     \u002F\u002F one handler for any step\n",[19,229,230,242,268,303,322,343],{"__ignoreMap":58},[62,231,232,235,237,240],{"class":64,"line":65},[62,233,234],{"class":111},"fetch",[62,236,123],{"class":85},[62,238,239],{"class":126},"'\u002Fapi\u002Fuser'",[62,241,136],{"class":85},[62,243,244,247,249,251,254,256,259,262,265],{"class":64,"line":108},[62,245,246],{"class":85},"  .",[62,248,151],{"class":111},[62,250,123],{"class":85},[62,252,253],{"class":89},"res",[62,255,159],{"class":68},[62,257,258],{"class":85}," res.",[62,260,261],{"class":111},"json",[62,263,264],{"class":85},"())              ",[62,266,267],{"class":171},"\u002F\u002F returns parsed body\n",[62,269,270,272,274,276,279,281,284,286,289,291,294,297,300],{"class":64,"line":139},[62,271,246],{"class":85},[62,273,151],{"class":111},[62,275,123],{"class":85},[62,277,278],{"class":89},"user",[62,280,159],{"class":68},[62,282,283],{"class":111}," fetch",[62,285,123],{"class":85},[62,287,288],{"class":126},"`\u002Fposts\u002F${",[62,290,278],{"class":85},[62,292,293],{"class":126},".",[62,295,296],{"class":85},"id",[62,298,299],{"class":126},"}`",[62,301,302],{"class":85},"))\n",[62,304,305,307,309,311,313,315,317,319],{"class":64,"line":145},[62,306,246],{"class":85},[62,308,151],{"class":111},[62,310,123],{"class":85},[62,312,253],{"class":89},[62,314,159],{"class":68},[62,316,258],{"class":85},[62,318,261],{"class":111},[62,320,321],{"class":85},"())\n",[62,323,325,327,329,331,334,336,338,340],{"class":64,"line":324},5,[62,326,246],{"class":85},[62,328,151],{"class":111},[62,330,123],{"class":85},[62,332,333],{"class":89},"posts",[62,335,159],{"class":68},[62,337,162],{"class":85},[62,339,165],{"class":111},[62,341,342],{"class":85},"(posts))\n",[62,344,346,348,351,353,356,358,360,363,366],{"class":64,"line":345},6,[62,347,246],{"class":85},[62,349,350],{"class":111},"catch",[62,352,123],{"class":85},[62,354,355],{"class":89},"err",[62,357,159],{"class":68},[62,359,162],{"class":85},[62,361,362],{"class":111},"error",[62,364,365],{"class":85},"(err))     ",[62,367,368],{"class":171},"\u002F\u002F one handler for any step\n",[15,370,371,372,375,376,379,380,383,384,386,387,390],{},"Returning a value passes it down; ",[177,373,374],{},"returning a promise makes the chain wait for it","\n(flattening — promises never nest as ",[19,377,378],{},"Promise\u003CPromise\u003CT>>","); throwing rejects the\nchain. The classic bug is forgetting to ",[177,381,382],{},"return"," inside a ",[19,385,189],{},", which hands the\nnext step ",[19,388,389],{},"undefined",". Keep chains flat by returning rather than nesting.",[10,392,21],{"id":393},"asyncawait",[15,395,396,183,399,402,403,405,406,409,410,412,413,416],{},[19,397,398],{},"async",[19,400,401],{},"await"," is syntactic sugar over promises. An ",[19,404,398],{}," function ",[177,407,408],{},"always returns\na promise","; ",[19,411,401],{}," ",[177,414,415],{},"pauses"," the function until a promise settles, then resumes with\nits value.",[53,418,420],{"className":55,"code":419,"language":57,"meta":58,"style":58},"async function load() {\n  const res = await fetch('\u002Fapi')   \u002F\u002F pause until resolved\n  return res.json()                 \u002F\u002F the caller's promise adopts this\n}\n",[19,421,422,435,461,476],{"__ignoreMap":58},[62,423,424,426,429,432],{"class":64,"line":65},[62,425,398],{"class":68},[62,427,428],{"class":68}," function",[62,430,431],{"class":111}," load",[62,433,434],{"class":85},"() {\n",[62,436,437,440,443,445,448,450,452,455,458],{"class":64,"line":108},[62,438,439],{"class":68},"  const",[62,441,442],{"class":72}," res",[62,444,76],{"class":68},[62,446,447],{"class":68}," await",[62,449,283],{"class":111},[62,451,123],{"class":85},[62,453,454],{"class":126},"'\u002Fapi'",[62,456,457],{"class":85},")   ",[62,459,460],{"class":171},"\u002F\u002F pause until resolved\n",[62,462,463,466,468,470,473],{"class":64,"line":139},[62,464,465],{"class":68},"  return",[62,467,258],{"class":85},[62,469,261],{"class":111},[62,471,472],{"class":85},"()                 ",[62,474,475],{"class":171},"\u002F\u002F the caller's promise adopts this\n",[62,477,478],{"class":64,"line":145},[62,479,480],{"class":85},"}\n",[15,482,483,485,486,488,489,491,492,495],{},[19,484,401],{}," only suspends the current function — the rest of the program keeps running.\nUnder the hood, code after an ",[19,487,401],{}," becomes a ",[19,490,189],{}," continuation scheduled as a\nmicrotask, so it always runs after the current synchronous task. Even ",[19,493,494],{},"await 5"," (a\nnon-promise) defers one microtask tick.",[10,497,499],{"id":498},"error-handling","Error handling",[15,501,502,503,506,507,509,510,512,513,516,517,293],{},"With raw promises, attach ",[19,504,505],{},".catch()","; a single trailing ",[19,508,192],{}," handles a rejection\nfrom any prior step. With ",[19,511,21],{},", an awaited rejected promise ",[177,514,515],{},"throws",", so use\n",[19,518,519],{},"try\u002Fcatch",[53,521,523],{"className":55,"code":522,"language":57,"meta":58,"style":58},"try {\n  const data = await load()\n  use(data)\n} catch (err) {\n  console.error(err)\n} finally {\n  hideSpinner() \u002F\u002F runs on success or failure\n}\n",[19,524,525,532,548,556,566,576,585,597],{"__ignoreMap":58},[62,526,527,530],{"class":64,"line":65},[62,528,529],{"class":68},"try",[62,531,105],{"class":85},[62,533,534,536,539,541,543,545],{"class":64,"line":108},[62,535,439],{"class":68},[62,537,538],{"class":72}," data",[62,540,76],{"class":68},[62,542,447],{"class":68},[62,544,431],{"class":111},[62,546,547],{"class":85},"()\n",[62,549,550,553],{"class":64,"line":139},[62,551,552],{"class":111},"  use",[62,554,555],{"class":85},"(data)\n",[62,557,558,561,563],{"class":64,"line":145},[62,559,560],{"class":85},"} ",[62,562,350],{"class":68},[62,564,565],{"class":85}," (err) {\n",[62,567,568,571,573],{"class":64,"line":324},[62,569,570],{"class":85},"  console.",[62,572,362],{"class":111},[62,574,575],{"class":85},"(err)\n",[62,577,578,580,583],{"class":64,"line":345},[62,579,560],{"class":85},[62,581,582],{"class":68},"finally",[62,584,105],{"class":85},[62,586,588,591,594],{"class":64,"line":587},7,[62,589,590],{"class":111},"  hideSpinner",[62,592,593],{"class":85},"() ",[62,595,596],{"class":171},"\u002F\u002F runs on success or failure\n",[62,598,600],{"class":64,"line":599},8,[62,601,480],{"class":85},[15,603,604,605,607,608,610,611,613,614,616,617,620,621,624,625,628],{},"Throwing inside a ",[19,606,189],{}," rejects the promise it returns, so errors skip subsequent\n",[19,609,189],{},"s until a ",[19,612,192],{}," — exactly like synchronous ",[19,615,519],{},". A rejected promise\nwith ",[177,618,619],{},"no"," handler becomes an ",[177,622,623],{},"unhandled rejection",": browsers fire an\n",[19,626,627],{},"unhandledrejection"," event; Node warns and (recently) crashes. Always handle rejections\nat the source — a global handler is a safety net, not a substitute.",[10,630,632],{"id":631},"running-tasks-sequential-vs-parallel","Running tasks: sequential vs parallel",[15,634,635,636,639,640,643,644,647],{},"The difference is ",[207,637,638],{},"when"," you start each task. Awaiting in a loop is ",[177,641,642],{},"sequential"," —\noften an accidental performance bug. To run ",[177,645,646],{},"in parallel",", start them all, then await\ntogether.",[53,649,651],{"className":55,"code":650,"language":57,"meta":58,"style":58},"\u002F\u002F sequential: ~A + B + C\nfor (const url of urls) results.push(await fetch(url))\n\n\u002F\u002F parallel: ~max(A, B, C)\nconst results = await Promise.all(urls.map(url => fetch(url)))\n",[19,652,653,658,689,695,700],{"__ignoreMap":58},[62,654,655],{"class":64,"line":65},[62,656,657],{"class":171},"\u002F\u002F sequential: ~A + B + C\n",[62,659,660,663,666,668,671,674,677,680,682,684,686],{"class":64,"line":108},[62,661,662],{"class":68},"for",[62,664,665],{"class":85}," (",[62,667,69],{"class":68},[62,669,670],{"class":72}," url",[62,672,673],{"class":68}," of",[62,675,676],{"class":85}," urls) results.",[62,678,679],{"class":111},"push",[62,681,123],{"class":85},[62,683,401],{"class":68},[62,685,283],{"class":111},[62,687,688],{"class":85},"(url))\n",[62,690,691],{"class":64,"line":139},[62,692,694],{"emptyLinePlaceholder":693},true,"\n",[62,696,697],{"class":64,"line":145},[62,698,699],{"class":171},"\u002F\u002F parallel: ~max(A, B, C)\n",[62,701,702,704,707,709,711,713,715,718,721,724,726,729,731,733],{"class":64,"line":324},[62,703,69],{"class":68},[62,705,706],{"class":72}," results",[62,708,76],{"class":68},[62,710,447],{"class":68},[62,712,82],{"class":72},[62,714,293],{"class":85},[62,716,717],{"class":111},"all",[62,719,720],{"class":85},"(urls.",[62,722,723],{"class":111},"map",[62,725,123],{"class":85},[62,727,728],{"class":89},"url",[62,730,159],{"class":68},[62,732,283],{"class":111},[62,734,735],{"class":85},"(url)))\n",[15,737,738,739,742],{},"Use sequential when each step depends on the previous one or you must respect a rate\nlimit; use parallel for independent work. For thousands of tasks, cap the in-flight\ncount with a concurrency limit (a worker pool, or a library like ",[19,740,741],{},"p-limit",") so you\ndon't overwhelm the server.",[15,744,745,746,749,750,753,754,756,757,760,761,763,764,767],{},"A common gotcha: ",[19,747,748],{},"forEach"," is ",[177,751,752],{},"not async-aware"," — it ignores the callback's returned\npromise, so ",[19,755,401],{}," inside it does nothing useful. Use ",[19,758,759],{},"for...of"," (sequential) or\n",[19,762,723],{}," + ",[19,765,766],{},"Promise.all"," (parallel).",[10,769,771],{"id":770},"the-combinators","The combinators",[53,773,775],{"className":55,"code":774,"language":57,"meta":58,"style":58},"await Promise.all([a, b, c])        \u002F\u002F all values, but rejects as soon as ANY rejects\nawait Promise.allSettled([a, b, c]) \u002F\u002F waits for all; never rejects; {status, value|reason}[]\nawait Promise.race([a, b])          \u002F\u002F first to SETTLE (fulfill or reject) wins\nawait Promise.any([a, b])           \u002F\u002F first to FULFILL; rejects only if all reject\n",[19,776,777,793,810,827],{"__ignoreMap":58},[62,778,779,781,783,785,787,790],{"class":64,"line":65},[62,780,401],{"class":68},[62,782,82],{"class":72},[62,784,293],{"class":85},[62,786,717],{"class":111},[62,788,789],{"class":85},"([a, b, c])        ",[62,791,792],{"class":171},"\u002F\u002F all values, but rejects as soon as ANY rejects\n",[62,794,795,797,799,801,804,807],{"class":64,"line":108},[62,796,401],{"class":68},[62,798,82],{"class":72},[62,800,293],{"class":85},[62,802,803],{"class":111},"allSettled",[62,805,806],{"class":85},"([a, b, c]) ",[62,808,809],{"class":171},"\u002F\u002F waits for all; never rejects; {status, value|reason}[]\n",[62,811,812,814,816,818,821,824],{"class":64,"line":139},[62,813,401],{"class":68},[62,815,82],{"class":72},[62,817,293],{"class":85},[62,819,820],{"class":111},"race",[62,822,823],{"class":85},"([a, b])          ",[62,825,826],{"class":171},"\u002F\u002F first to SETTLE (fulfill or reject) wins\n",[62,828,829,831,833,835,838,841],{"class":64,"line":145},[62,830,401],{"class":68},[62,832,82],{"class":72},[62,834,293],{"class":85},[62,836,837],{"class":111},"any",[62,839,840],{"class":85},"([a, b])           ",[62,842,843],{"class":171},"\u002F\u002F first to FULFILL; rejects only if all reject\n",[31,845,846,851,856,861],{},[34,847,848,850],{},[19,849,717],{}," for all-or-nothing (one failure should abort).",[34,852,853,855],{},[19,854,803],{}," for partial failures — dashboards, batch jobs where you want every\nresult.",[34,857,858,860],{},[19,859,820],{}," for timeouts (\"work vs a timer\").",[34,862,863,865],{},[19,864,837],{}," for \"first success wins\" (fastest mirror).",[15,867,868,869,183,872,875,876,412,879,882,883,886,887,890,891,293],{},"Watch the empty-array edge cases: ",[19,870,871],{},"all([])",[19,873,874],{},"allSettled([])"," resolve immediately, but\n",[19,877,878],{},"any([])",[177,880,881],{},"rejects"," with ",[19,884,885],{},"AggregateError"," and ",[19,888,889],{},"race([])"," stays ",[177,892,893],{},"pending forever",[10,895,897],{"id":896},"converting-callbacks-and-cancellation","Converting callbacks and cancellation",[15,899,900,901,903,904,907,908,910],{},"Wrap a callback API in ",[19,902,204],{},", but ",[177,905,906],{},"only"," when it isn't already\npromise-based — wrapping an existing promise in ",[19,909,204],{}," is a well-known\nanti-pattern.",[53,912,914],{"className":55,"code":913,"language":57,"meta":58,"style":58},"const wait = ms => new Promise(resolve => setTimeout(resolve, ms))\n",[19,915,916],{"__ignoreMap":58},[62,917,918,920,923,925,928,930,932,934,936,938,940,943],{"class":64,"line":65},[62,919,69],{"class":68},[62,921,922],{"class":111}," wait",[62,924,76],{"class":68},[62,926,927],{"class":89}," ms",[62,929,159],{"class":68},[62,931,79],{"class":68},[62,933,82],{"class":72},[62,935,123],{"class":85},[62,937,90],{"class":89},[62,939,159],{"class":68},[62,941,942],{"class":111}," setTimeout",[62,944,945],{"class":85},"(resolve, ms))\n",[15,947,948,949,952,953,956,957,960,961,963,964,967],{},"Promises themselves ",[177,950,951],{},"can't be cancelled"," — once started they run to settlement. The\nstandard approach is an ",[19,954,955],{},"AbortController",": pass its ",[19,958,959],{},"signal"," to ",[19,962,234],{},"\u002Ftimers and call\n",[19,965,966],{},"abort()"," to stop the underlying work.",[53,969,971],{"className":55,"code":970,"language":57,"meta":58,"style":58},"const ctrl = new AbortController()\nfetch('\u002Fslow', { signal: ctrl.signal }).catch(e => {\n  if (e.name === 'AbortError') console.log('cancelled')\n})\nctrl.abort()\n",[19,972,973,989,1012,1038,1042],{"__ignoreMap":58},[62,974,975,977,980,982,984,987],{"class":64,"line":65},[62,976,69],{"class":68},[62,978,979],{"class":72}," ctrl",[62,981,76],{"class":68},[62,983,79],{"class":68},[62,985,986],{"class":111}," AbortController",[62,988,547],{"class":85},[62,990,991,993,995,998,1001,1003,1005,1008,1010],{"class":64,"line":108},[62,992,234],{"class":111},[62,994,123],{"class":85},[62,996,997],{"class":126},"'\u002Fslow'",[62,999,1000],{"class":85},", { signal: ctrl.signal }).",[62,1002,350],{"class":111},[62,1004,123],{"class":85},[62,1006,1007],{"class":89},"e",[62,1009,159],{"class":68},[62,1011,105],{"class":85},[62,1013,1014,1017,1020,1023,1026,1029,1031,1033,1036],{"class":64,"line":139},[62,1015,1016],{"class":68},"  if",[62,1018,1019],{"class":85}," (e.name ",[62,1021,1022],{"class":68},"===",[62,1024,1025],{"class":126}," 'AbortError'",[62,1027,1028],{"class":85},") console.",[62,1030,165],{"class":111},[62,1032,123],{"class":85},[62,1034,1035],{"class":126},"'cancelled'",[62,1037,136],{"class":85},[62,1039,1040],{"class":64,"line":145},[62,1041,142],{"class":85},[62,1043,1044,1047,1050],{"class":64,"line":324},[62,1045,1046],{"class":85},"ctrl.",[62,1048,1049],{"class":111},"abort",[62,1051,547],{"class":85},[10,1053,1055],{"id":1054},"why-microtasks-matter-here","Why microtasks matter here",[53,1057,1059],{"className":55,"code":1058,"language":57,"meta":58,"style":58},"console.log(1)\nsetTimeout(() => console.log(2), 0)         \u002F\u002F macrotask\nPromise.resolve().then(() => console.log(3)) \u002F\u002F microtask\nconsole.log(4)\n\u002F\u002F 1, 4, 3, 2\n",[19,1060,1061,1075,1104,1137,1150],{"__ignoreMap":58},[62,1062,1063,1066,1068,1070,1073],{"class":64,"line":65},[62,1064,1065],{"class":85},"console.",[62,1067,165],{"class":111},[62,1069,123],{"class":85},[62,1071,1072],{"class":72},"1",[62,1074,136],{"class":85},[62,1076,1077,1080,1082,1084,1086,1088,1090,1093,1095,1098,1101],{"class":64,"line":108},[62,1078,1079],{"class":111},"setTimeout",[62,1081,115],{"class":85},[62,1083,102],{"class":68},[62,1085,162],{"class":85},[62,1087,165],{"class":111},[62,1089,123],{"class":85},[62,1091,1092],{"class":72},"2",[62,1094,130],{"class":85},[62,1096,1097],{"class":72},"0",[62,1099,1100],{"class":85},")         ",[62,1102,1103],{"class":171},"\u002F\u002F macrotask\n",[62,1105,1106,1109,1111,1113,1116,1118,1120,1122,1124,1126,1128,1131,1134],{"class":64,"line":139},[62,1107,1108],{"class":72},"Promise",[62,1110,293],{"class":85},[62,1112,90],{"class":111},[62,1114,1115],{"class":85},"().",[62,1117,151],{"class":111},[62,1119,115],{"class":85},[62,1121,102],{"class":68},[62,1123,162],{"class":85},[62,1125,165],{"class":111},[62,1127,123],{"class":85},[62,1129,1130],{"class":72},"3",[62,1132,1133],{"class":85},")) ",[62,1135,1136],{"class":171},"\u002F\u002F microtask\n",[62,1138,1139,1141,1143,1145,1148],{"class":64,"line":145},[62,1140,1065],{"class":85},[62,1142,165],{"class":111},[62,1144,123],{"class":85},[62,1146,1147],{"class":72},"4",[62,1149,136],{"class":85},[62,1151,1152],{"class":64,"line":324},[62,1153,1154],{"class":171},"\u002F\u002F 1, 4, 3, 2\n",[15,1156,1157,1158,1161,1162,1164,1165,1167],{},"Promise continuations are microtasks, which drain after the current synchronous code\nand ",[177,1159,1160],{},"before"," the next macrotask (",[19,1163,1079],{},"). That's why a resolved promise's\n",[19,1166,189],{}," always runs before a timer — a favorite interview puzzle.",[10,1169,1171],{"id":1170},"recap","Recap",[15,1173,1174,1175,1177,1178,1182,1183,1185,1186,1188,1189,1191,1192,1195,1196,1199,1200,1202,1203,1206],{},"A promise is a one-time, immutable representation of a future value. ",[177,1176,214],{},"\nsequences async steps (return values to pass them down, return promises to wait);\n",[177,1179,1180],{},[19,1181,21],{}," makes that read synchronously. Handle errors with ",[19,1184,192],{}," or\n",[19,1187,519],{},", and never leave a rejection unhandled. Choose ",[177,1190,642],{}," vs\n",[177,1193,1194],{},"parallel"," deliberately, pick the right ",[177,1197,1198],{},"combinator"," for your failure semantics,\nuse ",[19,1201,955],{}," to cancel, and remember promise callbacks are ",[177,1204,1205],{},"microtasks"," that\nbeat timers. With those pieces, asynchronous JavaScript stops being a source of\nsurprises.",[1208,1209,1210],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .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);}",{"title":58,"searchDepth":108,"depth":108,"links":1212},[1213,1214,1215,1216,1217,1218,1219,1220,1221,1222],{"id":12,"depth":108,"text":13},{"id":25,"depth":108,"text":26},{"id":213,"depth":108,"text":214},{"id":393,"depth":108,"text":21},{"id":498,"depth":108,"text":499},{"id":631,"depth":108,"text":632},{"id":770,"depth":108,"text":771},{"id":896,"depth":108,"text":897},{"id":1054,"depth":108,"text":1055},{"id":1170,"depth":108,"text":1171},"JavaScript promise and async\u002Fawait interview questions — states, chaining, error handling, Promise.all vs race, and converting callbacks.","medium","md","JavaScript","javascript",{},"\u002Fblog\u002Fjavascript-promises-async-await","\u002Fjavascript\u002Fasync\u002Fpromises",{"title":5,"description":1223},"blog\u002Fjavascript-promises-async-await","Promises & async\u002Fawait","Asynchronous JavaScript","2026-06-17","JLwxxnppDYyAkOK3SGjgK1bPinnl9fBjkbnR4SkL2sg",1781808673080]