[{"data":1,"prerenderedAt":2400},["ShallowReactive",2],{"doc-\u002Fdocs\u002Fjs-promise-async":3,"docs-all":2219},{"id":4,"title":5,"body":6,"category":2204,"date":2205,"description":2206,"draft":2207,"extension":2208,"meta":2209,"navigation":413,"path":2210,"seo":2211,"source":2212,"stem":2213,"tags":2214,"__hash__":2218},"docs\u002Fdocs\u002Fjs-promise-async.md","Promise、Generator 与 async\u002Fawait",{"type":7,"value":8,"toc":2188},"minimark",[9,14,18,30,35,42,201,251,270,274,481,496,500,510,674,677,807,811,825,1030,1035,1039,1103,1106,1389,1403,1407,1426,1550,1553,1557,1560,1738,1748,1871,1874,1878,1881,1998,2001,2004,2121,2128,2131,2138,2141,2184],[10,11,13],"h1",{"id":12},"javascript-异步编程","JavaScript 异步编程",[15,16,17],"p",{},"课程用 jQuery 请求外部接口说明异步流程。这里保留成功、失败、链式依赖和并发的教学目的，改用本地数据与短定时器，各示例独立运行。",[15,19,20,21,25,26,29],{},"Promise、Generator 属于 ES2015，async\u002Fawait 属于 ES2017，",[22,23,24],"code",{},"finally"," 属于 ES2018，",[22,27,28],{},"allSettled"," 属于 ES2020。",[31,32,34],"h2",{"id":33},"创建-promise","创建 Promise",[15,36,37,38,41],{},"Promise 描述一个最终可能成功或失败的结果。执行器同步执行；注册在 ",[22,39,40],{},"then"," 上的回调异步执行，不会在当前同步调用栈中立即运行。",[43,44,49],"pre",{"className":45,"code":46,"language":47,"meta":48,"style":48},"language-js shiki shiki-themes github-light github-dark","const events = [];\nconst promise = new Promise(resolve => {\n  events.push('executor');\n  resolve(123);\n});\npromise.then(value => {\n  events.push(value);\n  console.log(events); \u002F\u002F ['executor', 'sync', 123]\n});\nevents.push('sync');\n","js","",[22,50,51,71,100,119,132,138,155,165,181,186],{"__ignoreMap":48},[52,53,56,60,64,67],"span",{"class":54,"line":55},"line",1,[52,57,59],{"class":58},"szBVR","const",[52,61,63],{"class":62},"sj4cs"," events",[52,65,66],{"class":58}," =",[52,68,70],{"class":69},"sVt8B"," [];\n",[52,72,74,76,79,81,84,87,90,94,97],{"class":54,"line":73},2,[52,75,59],{"class":58},[52,77,78],{"class":62}," promise",[52,80,66],{"class":58},[52,82,83],{"class":58}," new",[52,85,86],{"class":62}," Promise",[52,88,89],{"class":69},"(",[52,91,93],{"class":92},"s4XuR","resolve",[52,95,96],{"class":58}," =>",[52,98,99],{"class":69}," {\n",[52,101,103,106,110,112,116],{"class":54,"line":102},3,[52,104,105],{"class":69},"  events.",[52,107,109],{"class":108},"sScJk","push",[52,111,89],{"class":69},[52,113,115],{"class":114},"sZZnC","'executor'",[52,117,118],{"class":69},");\n",[52,120,122,125,127,130],{"class":54,"line":121},4,[52,123,124],{"class":108},"  resolve",[52,126,89],{"class":69},[52,128,129],{"class":62},"123",[52,131,118],{"class":69},[52,133,135],{"class":54,"line":134},5,[52,136,137],{"class":69},"});\n",[52,139,141,144,146,148,151,153],{"class":54,"line":140},6,[52,142,143],{"class":69},"promise.",[52,145,40],{"class":108},[52,147,89],{"class":69},[52,149,150],{"class":92},"value",[52,152,96],{"class":58},[52,154,99],{"class":69},[52,156,158,160,162],{"class":54,"line":157},7,[52,159,105],{"class":69},[52,161,109],{"class":108},[52,163,164],{"class":69},"(value);\n",[52,166,168,171,174,177],{"class":54,"line":167},8,[52,169,170],{"class":69},"  console.",[52,172,173],{"class":108},"log",[52,175,176],{"class":69},"(events); ",[52,178,180],{"class":179},"sJ8bj","\u002F\u002F ['executor', 'sync', 123]\n",[52,182,184],{"class":54,"line":183},9,[52,185,137],{"class":69},[52,187,189,192,194,196,199],{"class":54,"line":188},10,[52,190,191],{"class":69},"events.",[52,193,109],{"class":108},[52,195,89],{"class":69},[52,197,198],{"class":114},"'sync'",[52,200,118],{"class":69},[202,203,204,217],"table",{},[205,206,207],"thead",{},[208,209,210,214],"tr",{},[211,212,213],"th",{},"状态",[211,215,216],{},"含义",[218,219,220,231,241],"tbody",{},[208,221,222,228],{},[223,224,225],"td",{},[22,226,227],{},"pending",[223,229,230],{},"尚未兑现或拒绝",[208,232,233,238],{},[223,234,235],{},[22,236,237],{},"fulfilled",[223,239,240],{},"已兑现，有结果值",[208,242,243,248],{},[223,244,245],{},[22,246,247],{},"rejected",[223,249,250],{},"已拒绝，有原因",[15,252,253,254,257,258,261,262,269],{},"从 pending 进入 fulfilled 或 rejected 后，状态不能再改变。",[22,255,256],{},"resolved"," 不是第四种状态，也不总等于 fulfilled：调用 ",[22,259,260],{},"resolve(另一个 Promise)"," 会跟随它，仍可能暂时 pending 或最终 rejected。",[263,264,268],"a",{"href":265,"rel":266},"https:\u002F\u002Ftc39.es\u002Fecma262\u002Fmultipage\u002Fcontrol-abstraction-objects.html#sec-promise-objects",[267],"nofollow","ECMAScript Promise 规范","。",[271,272,273],"h3",{"id":273},"封装回调式异步任务",[43,275,277],{"className":45,"code":276,"language":47,"meta":48,"style":48},"function requestMock(shouldFail = false) {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      if (shouldFail) reject(new Error('模拟请求失败'));\n      else resolve({ id: 1, title: '课程示例' });\n    }, 10);\n  });\n}\n\nrequestMock().then(data => console.log(data.title)).catch(console.error); \u002F\u002F 课程示例\nrequestMock(true).catch(error => console.log(error.message)); \u002F\u002F 模拟请求失败\n",[22,278,279,300,328,340,366,389,399,404,409,415,449],{"__ignoreMap":48},[52,280,281,284,287,289,292,294,297],{"class":54,"line":55},[52,282,283],{"class":58},"function",[52,285,286],{"class":108}," requestMock",[52,288,89],{"class":69},[52,290,291],{"class":92},"shouldFail",[52,293,66],{"class":58},[52,295,296],{"class":62}," false",[52,298,299],{"class":69},") {\n",[52,301,302,305,307,309,312,314,317,320,323,326],{"class":54,"line":73},[52,303,304],{"class":58},"  return",[52,306,83],{"class":58},[52,308,86],{"class":62},[52,310,311],{"class":69},"((",[52,313,93],{"class":92},[52,315,316],{"class":69},", ",[52,318,319],{"class":92},"reject",[52,321,322],{"class":69},") ",[52,324,325],{"class":58},"=>",[52,327,99],{"class":69},[52,329,330,333,336,338],{"class":54,"line":102},[52,331,332],{"class":108},"    setTimeout",[52,334,335],{"class":69},"(() ",[52,337,325],{"class":58},[52,339,99],{"class":69},[52,341,342,345,348,350,352,355,358,360,363],{"class":54,"line":121},[52,343,344],{"class":58},"      if",[52,346,347],{"class":69}," (shouldFail) ",[52,349,319],{"class":108},[52,351,89],{"class":69},[52,353,354],{"class":58},"new",[52,356,357],{"class":108}," Error",[52,359,89],{"class":69},[52,361,362],{"class":114},"'模拟请求失败'",[52,364,365],{"class":69},"));\n",[52,367,368,371,374,377,380,383,386],{"class":54,"line":134},[52,369,370],{"class":58},"      else",[52,372,373],{"class":108}," resolve",[52,375,376],{"class":69},"({ id: ",[52,378,379],{"class":62},"1",[52,381,382],{"class":69},", title: ",[52,384,385],{"class":114},"'课程示例'",[52,387,388],{"class":69}," });\n",[52,390,391,394,397],{"class":54,"line":140},[52,392,393],{"class":69},"    }, ",[52,395,396],{"class":62},"10",[52,398,118],{"class":69},[52,400,401],{"class":54,"line":157},[52,402,403],{"class":69},"  });\n",[52,405,406],{"class":54,"line":167},[52,407,408],{"class":69},"}\n",[52,410,411],{"class":54,"line":183},[52,412,414],{"emptyLinePlaceholder":413},true,"\n",[52,416,417,420,423,425,427,430,432,435,437,440,443,446],{"class":54,"line":188},[52,418,419],{"class":108},"requestMock",[52,421,422],{"class":69},"().",[52,424,40],{"class":108},[52,426,89],{"class":69},[52,428,429],{"class":92},"data",[52,431,96],{"class":58},[52,433,434],{"class":69}," console.",[52,436,173],{"class":108},[52,438,439],{"class":69},"(data.title)).",[52,441,442],{"class":108},"catch",[52,444,445],{"class":69},"(console.error); ",[52,447,448],{"class":179},"\u002F\u002F 课程示例\n",[52,450,452,454,456,459,462,464,466,469,471,473,475,478],{"class":54,"line":451},11,[52,453,419],{"class":108},[52,455,89],{"class":69},[52,457,458],{"class":62},"true",[52,460,461],{"class":69},").",[52,463,442],{"class":108},[52,465,89],{"class":69},[52,467,468],{"class":92},"error",[52,470,96],{"class":58},[52,472,434],{"class":69},[52,474,173],{"class":108},[52,476,477],{"class":69},"(error.message)); ",[52,479,480],{"class":179},"\u002F\u002F 模拟请求失败\n",[15,482,483,484,487,488,491,492,495],{},"原 jQuery ",[22,485,486],{},"$.ajax"," 的映射是 ",[22,489,490],{},"success → resolve","、",[22,493,494],{},"error → reject","。Promise 不限于网络请求，也可以封装文件、图片或其他回调；执行器中的异步回调若自行抛错，不会被构造器自动捕获，应显式捕获并调用 reject。",[31,497,499],{"id":498},"then-返回新的-promise","then 返回新的 Promise",[15,501,502,505,506,509],{},[22,503,504],{},"then(onFulfilled, onRejected)"," 返回新的 Promise。回调返回普通值，则下游得到该值；没有 return 得到 ",[22,507,508],{},"undefined","；返回 Promise 或 thenable 则跟随其结果；抛异常则下游拒绝。",[43,511,513],{"className":45,"code":512,"language":47,"meta":48,"style":48},"const original = Promise.resolve(10);\nconst next = original.then(value => value * 2);\nconsole.log(original === next); \u002F\u002F false\nnext\n  .then(value => Promise.resolve(value + 3))\n  .then(value => console.log(value)) \u002F\u002F 23\n  .then(value => console.log(value === undefined)); \u002F\u002F true\n",[22,514,515,537,568,587,592,623,645],{"__ignoreMap":48},[52,516,517,519,522,524,526,529,531,533,535],{"class":54,"line":55},[52,518,59],{"class":58},[52,520,521],{"class":62}," original",[52,523,66],{"class":58},[52,525,86],{"class":62},[52,527,528],{"class":69},".",[52,530,93],{"class":108},[52,532,89],{"class":69},[52,534,396],{"class":62},[52,536,118],{"class":69},[52,538,539,541,544,546,549,551,553,555,557,560,563,566],{"class":54,"line":73},[52,540,59],{"class":58},[52,542,543],{"class":62}," next",[52,545,66],{"class":58},[52,547,548],{"class":69}," original.",[52,550,40],{"class":108},[52,552,89],{"class":69},[52,554,150],{"class":92},[52,556,96],{"class":58},[52,558,559],{"class":69}," value ",[52,561,562],{"class":58},"*",[52,564,565],{"class":62}," 2",[52,567,118],{"class":69},[52,569,570,573,575,578,581,584],{"class":54,"line":102},[52,571,572],{"class":69},"console.",[52,574,173],{"class":108},[52,576,577],{"class":69},"(original ",[52,579,580],{"class":58},"===",[52,582,583],{"class":69}," next); ",[52,585,586],{"class":179},"\u002F\u002F false\n",[52,588,589],{"class":54,"line":121},[52,590,591],{"class":69},"next\n",[52,593,594,597,599,601,603,605,607,609,611,614,617,620],{"class":54,"line":134},[52,595,596],{"class":69},"  .",[52,598,40],{"class":108},[52,600,89],{"class":69},[52,602,150],{"class":92},[52,604,96],{"class":58},[52,606,86],{"class":62},[52,608,528],{"class":69},[52,610,93],{"class":108},[52,612,613],{"class":69},"(value ",[52,615,616],{"class":58},"+",[52,618,619],{"class":62}," 3",[52,621,622],{"class":69},"))\n",[52,624,625,627,629,631,633,635,637,639,642],{"class":54,"line":140},[52,626,596],{"class":69},[52,628,40],{"class":108},[52,630,89],{"class":69},[52,632,150],{"class":92},[52,634,96],{"class":58},[52,636,434],{"class":69},[52,638,173],{"class":108},[52,640,641],{"class":69},"(value)) ",[52,643,644],{"class":179},"\u002F\u002F 23\n",[52,646,647,649,651,653,655,657,659,661,663,665,668,671],{"class":54,"line":157},[52,648,596],{"class":69},[52,650,40],{"class":108},[52,652,89],{"class":69},[52,654,150],{"class":92},[52,656,96],{"class":58},[52,658,434],{"class":69},[52,660,173],{"class":108},[52,662,613],{"class":69},[52,664,580],{"class":58},[52,666,667],{"class":62}," undefined",[52,669,670],{"class":69},")); ",[52,672,673],{"class":179},"\u002F\u002F true\n",[15,675,676],{},"有依赖的异步操作应返回下一个 Promise，避免出现“启动了任务却没有让链等待”的情况。",[43,678,680],{"className":45,"code":679,"language":47,"meta":48,"style":48},"function getUser() { return Promise.resolve({ id: 1 }); }\nfunction getArticles(userId) { return Promise.resolve([`article-${userId}`]); }\n\ngetUser()\n  .then(user => getArticles(user.id))\n  .then(articles => console.log(articles)) \u002F\u002F ['article-1']\n  .catch(console.error);\n",[22,681,682,708,745,749,757,775,798],{"__ignoreMap":48},[52,683,684,686,689,692,695,697,699,701,703,705],{"class":54,"line":55},[52,685,283],{"class":58},[52,687,688],{"class":108}," getUser",[52,690,691],{"class":69},"() { ",[52,693,694],{"class":58},"return",[52,696,86],{"class":62},[52,698,528],{"class":69},[52,700,93],{"class":108},[52,702,376],{"class":69},[52,704,379],{"class":62},[52,706,707],{"class":69}," }); }\n",[52,709,710,712,715,717,720,723,725,727,729,731,734,737,739,742],{"class":54,"line":73},[52,711,283],{"class":58},[52,713,714],{"class":108}," getArticles",[52,716,89],{"class":69},[52,718,719],{"class":92},"userId",[52,721,722],{"class":69},") { ",[52,724,694],{"class":58},[52,726,86],{"class":62},[52,728,528],{"class":69},[52,730,93],{"class":108},[52,732,733],{"class":69},"([",[52,735,736],{"class":114},"`article-${",[52,738,719],{"class":69},[52,740,741],{"class":114},"}`",[52,743,744],{"class":69},"]); }\n",[52,746,747],{"class":54,"line":102},[52,748,414],{"emptyLinePlaceholder":413},[52,750,751,754],{"class":54,"line":121},[52,752,753],{"class":108},"getUser",[52,755,756],{"class":69},"()\n",[52,758,759,761,763,765,768,770,772],{"class":54,"line":134},[52,760,596],{"class":69},[52,762,40],{"class":108},[52,764,89],{"class":69},[52,766,767],{"class":92},"user",[52,769,96],{"class":58},[52,771,714],{"class":108},[52,773,774],{"class":69},"(user.id))\n",[52,776,777,779,781,783,786,788,790,792,795],{"class":54,"line":140},[52,778,596],{"class":69},[52,780,40],{"class":108},[52,782,89],{"class":69},[52,784,785],{"class":92},"articles",[52,787,96],{"class":58},[52,789,434],{"class":69},[52,791,173],{"class":108},[52,793,794],{"class":69},"(articles)) ",[52,796,797],{"class":179},"\u002F\u002F ['article-1']\n",[52,799,800,802,804],{"class":54,"line":157},[52,801,596],{"class":69},[52,803,442],{"class":108},[52,805,806],{"class":69},"(console.error);\n",[31,808,810],{"id":809},"catch-与-finally","catch 与 finally",[15,812,813,816,817,820,821,824],{},[22,814,815],{},"catch(onRejected)"," 等价于 ",[22,818,819],{},"then(undefined, onRejected)","，处理传到当前链位置的拒绝；不会捕获不属于这条链的所有异常。",[22,822,823],{},"then(success, failure)"," 中的 failure 也不会捕获同一个 success 回调抛出的错误，需要后续 catch。",[43,826,828],{"className":45,"code":827,"language":47,"meta":48,"style":48},"Promise.reject(new Error('第一次失败'))\n  .catch(error => {\n    console.log(error.message); \u002F\u002F 第一次失败\n    return 88; \u002F\u002F 恢复为成功结果\n  })\n  .then(value => {\n    console.log(value); \u002F\u002F 88\n    throw new Error('第二次失败');\n  })\n  .catch(error => {\n    console.log(error.message); \u002F\u002F 第二次失败\n    return 99;\n  })\n  .finally(() => console.log('收尾'))\n  .then(value => console.log(value)); \u002F\u002F 99\n",[22,829,830,852,866,879,893,898,912,924,940,944,958,969,980,985,1007],{"__ignoreMap":48},[52,831,832,835,837,839,841,843,845,847,850],{"class":54,"line":55},[52,833,834],{"class":62},"Promise",[52,836,528],{"class":69},[52,838,319],{"class":108},[52,840,89],{"class":69},[52,842,354],{"class":58},[52,844,357],{"class":108},[52,846,89],{"class":69},[52,848,849],{"class":114},"'第一次失败'",[52,851,622],{"class":69},[52,853,854,856,858,860,862,864],{"class":54,"line":73},[52,855,596],{"class":69},[52,857,442],{"class":108},[52,859,89],{"class":69},[52,861,468],{"class":92},[52,863,96],{"class":58},[52,865,99],{"class":69},[52,867,868,871,873,876],{"class":54,"line":102},[52,869,870],{"class":69},"    console.",[52,872,173],{"class":108},[52,874,875],{"class":69},"(error.message); ",[52,877,878],{"class":179},"\u002F\u002F 第一次失败\n",[52,880,881,884,887,890],{"class":54,"line":121},[52,882,883],{"class":58},"    return",[52,885,886],{"class":62}," 88",[52,888,889],{"class":69},"; ",[52,891,892],{"class":179},"\u002F\u002F 恢复为成功结果\n",[52,894,895],{"class":54,"line":134},[52,896,897],{"class":69},"  })\n",[52,899,900,902,904,906,908,910],{"class":54,"line":140},[52,901,596],{"class":69},[52,903,40],{"class":108},[52,905,89],{"class":69},[52,907,150],{"class":92},[52,909,96],{"class":58},[52,911,99],{"class":69},[52,913,914,916,918,921],{"class":54,"line":157},[52,915,870],{"class":69},[52,917,173],{"class":108},[52,919,920],{"class":69},"(value); ",[52,922,923],{"class":179},"\u002F\u002F 88\n",[52,925,926,929,931,933,935,938],{"class":54,"line":167},[52,927,928],{"class":58},"    throw",[52,930,83],{"class":58},[52,932,357],{"class":108},[52,934,89],{"class":69},[52,936,937],{"class":114},"'第二次失败'",[52,939,118],{"class":69},[52,941,942],{"class":54,"line":183},[52,943,897],{"class":69},[52,945,946,948,950,952,954,956],{"class":54,"line":188},[52,947,596],{"class":69},[52,949,442],{"class":108},[52,951,89],{"class":69},[52,953,468],{"class":92},[52,955,96],{"class":58},[52,957,99],{"class":69},[52,959,960,962,964,966],{"class":54,"line":451},[52,961,870],{"class":69},[52,963,173],{"class":108},[52,965,875],{"class":69},[52,967,968],{"class":179},"\u002F\u002F 第二次失败\n",[52,970,972,974,977],{"class":54,"line":971},12,[52,973,883],{"class":58},[52,975,976],{"class":62}," 99",[52,978,979],{"class":69},";\n",[52,981,983],{"class":54,"line":982},13,[52,984,897],{"class":69},[52,986,988,990,992,994,996,998,1000,1002,1005],{"class":54,"line":987},14,[52,989,596],{"class":69},[52,991,24],{"class":108},[52,993,335],{"class":69},[52,995,325],{"class":58},[52,997,434],{"class":69},[52,999,173],{"class":108},[52,1001,89],{"class":69},[52,1003,1004],{"class":114},"'收尾'",[52,1006,622],{"class":69},[52,1008,1010,1012,1014,1016,1018,1020,1022,1024,1027],{"class":54,"line":1009},15,[52,1011,596],{"class":69},[52,1013,40],{"class":108},[52,1015,89],{"class":69},[52,1017,150],{"class":92},[52,1019,96],{"class":58},[52,1021,434],{"class":69},[52,1023,173],{"class":108},[52,1025,1026],{"class":69},"(value)); ",[52,1028,1029],{"class":179},"\u002F\u002F 99\n",[15,1031,1032,1034],{},[22,1033,24],{}," 在上游落定后执行，不接收结果参数，适合收尾。正常返回不会替换原结果；但它若抛错或返回拒绝的 Promise，会使下游拒绝。若上游一直 pending，finally 也不会凭空执行。",[31,1036,1038],{"id":1037},"promise-组合方法","Promise 组合方法",[202,1040,1041,1051],{},[205,1042,1043],{},[208,1044,1045,1048],{},[211,1046,1047],{},"方法",[211,1049,1050],{},"行为",[218,1052,1053,1063,1073,1083,1093],{},[208,1054,1055,1060],{},[223,1056,1057],{},[22,1058,1059],{},"Promise.all(items)",[223,1061,1062],{},"全部成功后按输入顺序返回值数组；任一拒绝则整体拒绝",[208,1064,1065,1070],{},[223,1066,1067],{},[22,1068,1069],{},"Promise.race(items)",[223,1071,1072],{},"跟随最先落定的结果，可能成功也可能失败",[208,1074,1075,1080],{},[223,1076,1077],{},[22,1078,1079],{},"Promise.allSettled(items)",[223,1081,1082],{},"等待全部落定，按输入顺序返回各自状态和值或原因",[208,1084,1085,1090],{},[223,1086,1087],{},[22,1088,1089],{},"Promise.resolve(value)",[223,1091,1092],{},"得到采用 value 结果的 Promise，包括吸收 thenable",[208,1094,1095,1100],{},[223,1096,1097],{},[22,1098,1099],{},"Promise.reject(reason)",[223,1101,1102],{},"得到以 reason 拒绝的 Promise",[15,1104,1105],{},"组合方法不负责“启动”已有 Promise，也不会自动取消其他任务。",[43,1107,1109],{"className":45,"code":1108,"language":47,"meta":48,"style":48},"async function compare() {\n  const slow = new Promise(resolve => setTimeout(() => resolve('slow'), 20));\n  const fast = new Promise(resolve => setTimeout(() => resolve('fast'), 5));\n  const first = Promise.race([slow, fast]);\n  console.log(await first); \u002F\u002F fast\n  console.log(await Promise.all([slow, fast])); \u002F\u002F ['slow', 'fast']\n\n  const outcomes = await Promise.allSettled([\n    Promise.resolve(1),\n    Promise.reject(new Error('失败'))\n  ]);\n  console.log(outcomes.map(item => item.status)); \u002F\u002F ['fulfilled', 'rejected']\n  console.log(outcomes[1].reason.message); \u002F\u002F 失败\n}\ncompare().catch(console.error);\n",[22,1110,1111,1125,1167,1206,1225,1242,1265,1269,1290,1306,1327,1332,1357,1374,1378],{"__ignoreMap":48},[52,1112,1113,1116,1119,1122],{"class":54,"line":55},[52,1114,1115],{"class":58},"async",[52,1117,1118],{"class":58}," function",[52,1120,1121],{"class":108}," compare",[52,1123,1124],{"class":69},"() {\n",[52,1126,1127,1130,1133,1135,1137,1139,1141,1143,1145,1148,1150,1152,1154,1156,1159,1162,1165],{"class":54,"line":73},[52,1128,1129],{"class":58},"  const",[52,1131,1132],{"class":62}," slow",[52,1134,66],{"class":58},[52,1136,83],{"class":58},[52,1138,86],{"class":62},[52,1140,89],{"class":69},[52,1142,93],{"class":92},[52,1144,96],{"class":58},[52,1146,1147],{"class":108}," setTimeout",[52,1149,335],{"class":69},[52,1151,325],{"class":58},[52,1153,373],{"class":108},[52,1155,89],{"class":69},[52,1157,1158],{"class":114},"'slow'",[52,1160,1161],{"class":69},"), ",[52,1163,1164],{"class":62},"20",[52,1166,365],{"class":69},[52,1168,1169,1171,1174,1176,1178,1180,1182,1184,1186,1188,1190,1192,1194,1196,1199,1201,1204],{"class":54,"line":102},[52,1170,1129],{"class":58},[52,1172,1173],{"class":62}," fast",[52,1175,66],{"class":58},[52,1177,83],{"class":58},[52,1179,86],{"class":62},[52,1181,89],{"class":69},[52,1183,93],{"class":92},[52,1185,96],{"class":58},[52,1187,1147],{"class":108},[52,1189,335],{"class":69},[52,1191,325],{"class":58},[52,1193,373],{"class":108},[52,1195,89],{"class":69},[52,1197,1198],{"class":114},"'fast'",[52,1200,1161],{"class":69},[52,1202,1203],{"class":62},"5",[52,1205,365],{"class":69},[52,1207,1208,1210,1213,1215,1217,1219,1222],{"class":54,"line":121},[52,1209,1129],{"class":58},[52,1211,1212],{"class":62}," first",[52,1214,66],{"class":58},[52,1216,86],{"class":62},[52,1218,528],{"class":69},[52,1220,1221],{"class":108},"race",[52,1223,1224],{"class":69},"([slow, fast]);\n",[52,1226,1227,1229,1231,1233,1236,1239],{"class":54,"line":134},[52,1228,170],{"class":69},[52,1230,173],{"class":108},[52,1232,89],{"class":69},[52,1234,1235],{"class":58},"await",[52,1237,1238],{"class":69}," first); ",[52,1240,1241],{"class":179},"\u002F\u002F fast\n",[52,1243,1244,1246,1248,1250,1252,1254,1256,1259,1262],{"class":54,"line":140},[52,1245,170],{"class":69},[52,1247,173],{"class":108},[52,1249,89],{"class":69},[52,1251,1235],{"class":58},[52,1253,86],{"class":62},[52,1255,528],{"class":69},[52,1257,1258],{"class":108},"all",[52,1260,1261],{"class":69},"([slow, fast])); ",[52,1263,1264],{"class":179},"\u002F\u002F ['slow', 'fast']\n",[52,1266,1267],{"class":54,"line":157},[52,1268,414],{"emptyLinePlaceholder":413},[52,1270,1271,1273,1276,1278,1281,1283,1285,1287],{"class":54,"line":167},[52,1272,1129],{"class":58},[52,1274,1275],{"class":62}," outcomes",[52,1277,66],{"class":58},[52,1279,1280],{"class":58}," await",[52,1282,86],{"class":62},[52,1284,528],{"class":69},[52,1286,28],{"class":108},[52,1288,1289],{"class":69},"([\n",[52,1291,1292,1295,1297,1299,1301,1303],{"class":54,"line":183},[52,1293,1294],{"class":62},"    Promise",[52,1296,528],{"class":69},[52,1298,93],{"class":108},[52,1300,89],{"class":69},[52,1302,379],{"class":62},[52,1304,1305],{"class":69},"),\n",[52,1307,1308,1310,1312,1314,1316,1318,1320,1322,1325],{"class":54,"line":188},[52,1309,1294],{"class":62},[52,1311,528],{"class":69},[52,1313,319],{"class":108},[52,1315,89],{"class":69},[52,1317,354],{"class":58},[52,1319,357],{"class":108},[52,1321,89],{"class":69},[52,1323,1324],{"class":114},"'失败'",[52,1326,622],{"class":69},[52,1328,1329],{"class":54,"line":451},[52,1330,1331],{"class":69},"  ]);\n",[52,1333,1334,1336,1338,1341,1344,1346,1349,1351,1354],{"class":54,"line":971},[52,1335,170],{"class":69},[52,1337,173],{"class":108},[52,1339,1340],{"class":69},"(outcomes.",[52,1342,1343],{"class":108},"map",[52,1345,89],{"class":69},[52,1347,1348],{"class":92},"item",[52,1350,96],{"class":58},[52,1352,1353],{"class":69}," item.status)); ",[52,1355,1356],{"class":179},"\u002F\u002F ['fulfilled', 'rejected']\n",[52,1358,1359,1361,1363,1366,1368,1371],{"class":54,"line":982},[52,1360,170],{"class":69},[52,1362,173],{"class":108},[52,1364,1365],{"class":69},"(outcomes[",[52,1367,379],{"class":62},[52,1369,1370],{"class":69},"].reason.message); ",[52,1372,1373],{"class":179},"\u002F\u002F 失败\n",[52,1375,1376],{"class":54,"line":987},[52,1377,408],{"class":69},[52,1379,1380,1383,1385,1387],{"class":54,"line":1009},[52,1381,1382],{"class":108},"compare",[52,1384,422],{"class":69},[52,1386,442],{"class":108},[52,1388,806],{"class":69},[15,1390,1391,1392,491,1395,1398,1399,1402],{},"空集合的边界：",[22,1393,1394],{},"all([])",[22,1396,1397],{},"allSettled([])"," 兑现为空数组，",[22,1400,1401],{},"race([])"," 一直 pending。输入为空时也需要按业务意图选择。",[31,1404,1406],{"id":1405},"generator暂停与恢复","Generator：暂停与恢复",[15,1408,1409,1410,1413,1414,1417,1418,1421,1422,1425],{},"调用 ",[22,1411,1412],{},"function*"," 得到迭代器，并不立即执行函数体。",[22,1415,1416],{},"next()"," 推进到下一次 yield，返回 ",[22,1419,1420],{},"{ value, done }","；后续 ",[22,1423,1424],{},"next(value)"," 的参数成为上一次 yield 表达式的值。",[43,1427,1429],{"className":45,"code":1428,"language":47,"meta":48,"style":48},"function* steps() {\n  const input = yield 123;\n  yield input * 3;\n  return '结束';\n}\nconst iterator = steps();\nconsole.log(iterator.next()); \u002F\u002F { value: 123, done: false }\nconsole.log(iterator.next(10)); \u002F\u002F { value: 30, done: false }\nconsole.log(iterator.next()); \u002F\u002F { value: '结束', done: true }\n",[22,1430,1431,1440,1457,1471,1480,1484,1498,1516,1535],{"__ignoreMap":48},[52,1432,1433,1435,1438],{"class":54,"line":55},[52,1434,1412],{"class":58},[52,1436,1437],{"class":108}," steps",[52,1439,1124],{"class":69},[52,1441,1442,1444,1447,1449,1452,1455],{"class":54,"line":73},[52,1443,1129],{"class":58},[52,1445,1446],{"class":62}," input",[52,1448,66],{"class":58},[52,1450,1451],{"class":58}," yield",[52,1453,1454],{"class":62}," 123",[52,1456,979],{"class":69},[52,1458,1459,1462,1465,1467,1469],{"class":54,"line":102},[52,1460,1461],{"class":58},"  yield",[52,1463,1464],{"class":69}," input ",[52,1466,562],{"class":58},[52,1468,619],{"class":62},[52,1470,979],{"class":69},[52,1472,1473,1475,1478],{"class":54,"line":121},[52,1474,304],{"class":58},[52,1476,1477],{"class":114}," '结束'",[52,1479,979],{"class":69},[52,1481,1482],{"class":54,"line":134},[52,1483,408],{"class":69},[52,1485,1486,1488,1491,1493,1495],{"class":54,"line":140},[52,1487,59],{"class":58},[52,1489,1490],{"class":62}," iterator",[52,1492,66],{"class":58},[52,1494,1437],{"class":108},[52,1496,1497],{"class":69},"();\n",[52,1499,1500,1502,1504,1507,1510,1513],{"class":54,"line":157},[52,1501,572],{"class":69},[52,1503,173],{"class":108},[52,1505,1506],{"class":69},"(iterator.",[52,1508,1509],{"class":108},"next",[52,1511,1512],{"class":69},"()); ",[52,1514,1515],{"class":179},"\u002F\u002F { value: 123, done: false }\n",[52,1517,1518,1520,1522,1524,1526,1528,1530,1532],{"class":54,"line":167},[52,1519,572],{"class":69},[52,1521,173],{"class":108},[52,1523,1506],{"class":69},[52,1525,1509],{"class":108},[52,1527,89],{"class":69},[52,1529,396],{"class":62},[52,1531,670],{"class":69},[52,1533,1534],{"class":179},"\u002F\u002F { value: 30, done: false }\n",[52,1536,1537,1539,1541,1543,1545,1547],{"class":54,"line":183},[52,1538,572],{"class":69},[52,1540,173],{"class":108},[52,1542,1506],{"class":69},[52,1544,1509],{"class":108},[52,1546,1512],{"class":69},[52,1548,1549],{"class":179},"\u002F\u002F { value: '结束', done: true }\n",[15,1551,1552],{},"第一次 next 没有可接收参数的前一个 yield，所以传参没有这一作用。Generator 是通用的可暂停控制流程工具，并不局限于异步。",[271,1554,1556],{"id":1555},"yield-promise-不会自动等待","yield Promise 不会自动等待",[15,1558,1559],{},"需要调用方或执行器等待 Promise，再把结果传回迭代器。",[43,1561,1563],{"className":45,"code":1562,"language":47,"meta":48,"style":48},"function* steps() {\n  const a = yield Promise.resolve(123);\n  const b = yield Promise.resolve(a * 3);\n  return b;\n}\nasync function runTwoSteps() {\n  const iterator = steps();\n  const first = iterator.next();\n  const second = iterator.next(await first.value);\n  const last = iterator.next(await second.value);\n  console.log(last.value, last.done); \u002F\u002F 369 true\n}\nrunTwoSteps().catch(console.error);\n",[22,1564,1565,1573,1596,1622,1629,1633,1644,1656,1671,1691,1711,1723,1727],{"__ignoreMap":48},[52,1566,1567,1569,1571],{"class":54,"line":55},[52,1568,1412],{"class":58},[52,1570,1437],{"class":108},[52,1572,1124],{"class":69},[52,1574,1575,1577,1580,1582,1584,1586,1588,1590,1592,1594],{"class":54,"line":73},[52,1576,1129],{"class":58},[52,1578,1579],{"class":62}," a",[52,1581,66],{"class":58},[52,1583,1451],{"class":58},[52,1585,86],{"class":62},[52,1587,528],{"class":69},[52,1589,93],{"class":108},[52,1591,89],{"class":69},[52,1593,129],{"class":62},[52,1595,118],{"class":69},[52,1597,1598,1600,1603,1605,1607,1609,1611,1613,1616,1618,1620],{"class":54,"line":102},[52,1599,1129],{"class":58},[52,1601,1602],{"class":62}," b",[52,1604,66],{"class":58},[52,1606,1451],{"class":58},[52,1608,86],{"class":62},[52,1610,528],{"class":69},[52,1612,93],{"class":108},[52,1614,1615],{"class":69},"(a ",[52,1617,562],{"class":58},[52,1619,619],{"class":62},[52,1621,118],{"class":69},[52,1623,1624,1626],{"class":54,"line":121},[52,1625,304],{"class":58},[52,1627,1628],{"class":69}," b;\n",[52,1630,1631],{"class":54,"line":134},[52,1632,408],{"class":69},[52,1634,1635,1637,1639,1642],{"class":54,"line":140},[52,1636,1115],{"class":58},[52,1638,1118],{"class":58},[52,1640,1641],{"class":108}," runTwoSteps",[52,1643,1124],{"class":69},[52,1645,1646,1648,1650,1652,1654],{"class":54,"line":157},[52,1647,1129],{"class":58},[52,1649,1490],{"class":62},[52,1651,66],{"class":58},[52,1653,1437],{"class":108},[52,1655,1497],{"class":69},[52,1657,1658,1660,1662,1664,1667,1669],{"class":54,"line":167},[52,1659,1129],{"class":58},[52,1661,1212],{"class":62},[52,1663,66],{"class":58},[52,1665,1666],{"class":69}," iterator.",[52,1668,1509],{"class":108},[52,1670,1497],{"class":69},[52,1672,1673,1675,1678,1680,1682,1684,1686,1688],{"class":54,"line":183},[52,1674,1129],{"class":58},[52,1676,1677],{"class":62}," second",[52,1679,66],{"class":58},[52,1681,1666],{"class":69},[52,1683,1509],{"class":108},[52,1685,89],{"class":69},[52,1687,1235],{"class":58},[52,1689,1690],{"class":69}," first.value);\n",[52,1692,1693,1695,1698,1700,1702,1704,1706,1708],{"class":54,"line":188},[52,1694,1129],{"class":58},[52,1696,1697],{"class":62}," last",[52,1699,66],{"class":58},[52,1701,1666],{"class":69},[52,1703,1509],{"class":108},[52,1705,89],{"class":69},[52,1707,1235],{"class":58},[52,1709,1710],{"class":69}," second.value);\n",[52,1712,1713,1715,1717,1720],{"class":54,"line":451},[52,1714,170],{"class":69},[52,1716,173],{"class":108},[52,1718,1719],{"class":69},"(last.value, last.done); ",[52,1721,1722],{"class":179},"\u002F\u002F 369 true\n",[52,1724,1725],{"class":54,"line":971},[52,1726,408],{"class":69},[52,1728,1729,1732,1734,1736],{"class":54,"line":982},[52,1730,1731],{"class":108},"runTwoSteps",[52,1733,422],{"class":69},[52,1735,442],{"class":108},[52,1737,806],{"class":69},[15,1739,1740,1741,1744,1745,1747],{},"这只是两步示例，不是通用执行器。课程中 ",[22,1742,1743],{},"co"," 库处理执行器工作，其原调用方式作为 Node 代码片段保留，需已有 ",[22,1746,1743],{}," 依赖：",[43,1749,1751],{"className":45,"code":1750,"language":47,"meta":48,"style":48},"const co = require('co');\nfunction* task() {\n  const a = yield Promise.resolve(123);\n  const b = yield Promise.resolve(a * 3);\n  return b;\n}\nco(task()).then(value => console.log(value)).catch(console.error); \u002F\u002F 369\n",[22,1752,1753,1772,1781,1803,1827,1833,1837],{"__ignoreMap":48},[52,1754,1755,1757,1760,1762,1765,1767,1770],{"class":54,"line":55},[52,1756,59],{"class":58},[52,1758,1759],{"class":62}," co",[52,1761,66],{"class":58},[52,1763,1764],{"class":108}," require",[52,1766,89],{"class":69},[52,1768,1769],{"class":114},"'co'",[52,1771,118],{"class":69},[52,1773,1774,1776,1779],{"class":54,"line":73},[52,1775,1412],{"class":58},[52,1777,1778],{"class":108}," task",[52,1780,1124],{"class":69},[52,1782,1783,1785,1787,1789,1791,1793,1795,1797,1799,1801],{"class":54,"line":102},[52,1784,1129],{"class":58},[52,1786,1579],{"class":62},[52,1788,66],{"class":58},[52,1790,1451],{"class":58},[52,1792,86],{"class":62},[52,1794,528],{"class":69},[52,1796,93],{"class":108},[52,1798,89],{"class":69},[52,1800,129],{"class":62},[52,1802,118],{"class":69},[52,1804,1805,1807,1809,1811,1813,1815,1817,1819,1821,1823,1825],{"class":54,"line":121},[52,1806,1129],{"class":58},[52,1808,1602],{"class":62},[52,1810,66],{"class":58},[52,1812,1451],{"class":58},[52,1814,86],{"class":62},[52,1816,528],{"class":69},[52,1818,93],{"class":108},[52,1820,1615],{"class":69},[52,1822,562],{"class":58},[52,1824,619],{"class":62},[52,1826,118],{"class":69},[52,1828,1829,1831],{"class":54,"line":134},[52,1830,304],{"class":58},[52,1832,1628],{"class":69},[52,1834,1835],{"class":54,"line":140},[52,1836,408],{"class":69},[52,1838,1839,1841,1843,1846,1849,1851,1853,1855,1857,1859,1861,1864,1866,1868],{"class":54,"line":157},[52,1840,1743],{"class":108},[52,1842,89],{"class":69},[52,1844,1845],{"class":108},"task",[52,1847,1848],{"class":69},"()).",[52,1850,40],{"class":108},[52,1852,89],{"class":69},[52,1854,150],{"class":92},[52,1856,96],{"class":58},[52,1858,434],{"class":69},[52,1860,173],{"class":108},[52,1862,1863],{"class":69},"(value)).",[52,1865,442],{"class":108},[52,1867,445],{"class":69},[52,1869,1870],{"class":179},"\u002F\u002F 369\n",[15,1872,1873],{},"README 提到 redux-saga，只作为 Generator 应用方向记录；课程没有提供 saga 实现。",[31,1875,1877],{"id":1876},"asyncawait","async\u002Fawait",[15,1879,1880],{},"async 函数总返回 Promise。return 的值成为兑现结果，未捕获异常成为拒绝；await 暂停当前 async 函数的后续执行，不阻塞整个 JavaScript 线程。",[43,1882,1884],{"className":45,"code":1883,"language":47,"meta":48,"style":48},"async function calculate() {\n  const a = await new Promise(resolve => setTimeout(() => resolve(123), 10));\n  const b = await Promise.resolve(a * 10);\n  return b;\n}\ncalculate().then(value => console.log(value)).catch(console.error); \u002F\u002F 1230\n",[22,1885,1886,1897,1935,1960,1966,1970],{"__ignoreMap":48},[52,1887,1888,1890,1892,1895],{"class":54,"line":55},[52,1889,1115],{"class":58},[52,1891,1118],{"class":58},[52,1893,1894],{"class":108}," calculate",[52,1896,1124],{"class":69},[52,1898,1899,1901,1903,1905,1907,1909,1911,1913,1915,1917,1919,1921,1923,1925,1927,1929,1931,1933],{"class":54,"line":73},[52,1900,1129],{"class":58},[52,1902,1579],{"class":62},[52,1904,66],{"class":58},[52,1906,1280],{"class":58},[52,1908,83],{"class":58},[52,1910,86],{"class":62},[52,1912,89],{"class":69},[52,1914,93],{"class":92},[52,1916,96],{"class":58},[52,1918,1147],{"class":108},[52,1920,335],{"class":69},[52,1922,325],{"class":58},[52,1924,373],{"class":108},[52,1926,89],{"class":69},[52,1928,129],{"class":62},[52,1930,1161],{"class":69},[52,1932,396],{"class":62},[52,1934,365],{"class":69},[52,1936,1937,1939,1941,1943,1945,1947,1949,1951,1953,1955,1958],{"class":54,"line":102},[52,1938,1129],{"class":58},[52,1940,1602],{"class":62},[52,1942,66],{"class":58},[52,1944,1280],{"class":58},[52,1946,86],{"class":62},[52,1948,528],{"class":69},[52,1950,93],{"class":108},[52,1952,1615],{"class":69},[52,1954,562],{"class":58},[52,1956,1957],{"class":62}," 10",[52,1959,118],{"class":69},[52,1961,1962,1964],{"class":54,"line":121},[52,1963,304],{"class":58},[52,1965,1628],{"class":69},[52,1967,1968],{"class":54,"line":134},[52,1969,408],{"class":69},[52,1971,1972,1975,1977,1979,1981,1983,1985,1987,1989,1991,1993,1995],{"class":54,"line":140},[52,1973,1974],{"class":108},"calculate",[52,1976,422],{"class":69},[52,1978,40],{"class":108},[52,1980,89],{"class":69},[52,1982,150],{"class":92},[52,1984,96],{"class":58},[52,1986,434],{"class":69},[52,1988,173],{"class":108},[52,1990,1863],{"class":69},[52,1992,442],{"class":108},[52,1994,445],{"class":69},[52,1996,1997],{"class":179},"\u002F\u002F 1230\n",[15,1999,2000],{},"await 也接受普通值或 thenable，普通值相当于经过 Promise 解析再继续。课程所说“Generator + co”可帮助理解自动执行流程，但 async 函数不是 Generator，不能对它的返回值调用 next。",[271,2002,2003],{"id":2003},"拒绝与错误处理",[43,2005,2007],{"className":45,"code":2006,"language":47,"meta":48,"style":48},"async function recover() {\n  try {\n    await Promise.reject(new Error('模拟失败'));\n    return '不会执行';\n  } catch (error) {\n    return `已处理：${error.message}`;\n  }\n}\nrecover().then(value => console.log(value)); \u002F\u002F 已处理：模拟失败\n",[22,2008,2009,2020,2027,2051,2060,2070,2088,2093,2097],{"__ignoreMap":48},[52,2010,2011,2013,2015,2018],{"class":54,"line":55},[52,2012,1115],{"class":58},[52,2014,1118],{"class":58},[52,2016,2017],{"class":108}," recover",[52,2019,1124],{"class":69},[52,2021,2022,2025],{"class":54,"line":73},[52,2023,2024],{"class":58},"  try",[52,2026,99],{"class":69},[52,2028,2029,2032,2034,2036,2038,2040,2042,2044,2046,2049],{"class":54,"line":102},[52,2030,2031],{"class":58},"    await",[52,2033,86],{"class":62},[52,2035,528],{"class":69},[52,2037,319],{"class":108},[52,2039,89],{"class":69},[52,2041,354],{"class":58},[52,2043,357],{"class":108},[52,2045,89],{"class":69},[52,2047,2048],{"class":114},"'模拟失败'",[52,2050,365],{"class":69},[52,2052,2053,2055,2058],{"class":54,"line":121},[52,2054,883],{"class":58},[52,2056,2057],{"class":114}," '不会执行'",[52,2059,979],{"class":69},[52,2061,2062,2065,2067],{"class":54,"line":134},[52,2063,2064],{"class":69},"  } ",[52,2066,442],{"class":58},[52,2068,2069],{"class":69}," (error) {\n",[52,2071,2072,2074,2077,2079,2081,2084,2086],{"class":54,"line":140},[52,2073,883],{"class":58},[52,2075,2076],{"class":114}," `已处理：${",[52,2078,468],{"class":69},[52,2080,528],{"class":114},[52,2082,2083],{"class":69},"message",[52,2085,741],{"class":114},[52,2087,979],{"class":69},[52,2089,2090],{"class":54,"line":157},[52,2091,2092],{"class":69},"  }\n",[52,2094,2095],{"class":54,"line":167},[52,2096,408],{"class":69},[52,2098,2099,2102,2104,2106,2108,2110,2112,2114,2116,2118],{"class":54,"line":183},[52,2100,2101],{"class":108},"recover",[52,2103,422],{"class":69},[52,2105,40],{"class":108},[52,2107,89],{"class":69},[52,2109,150],{"class":92},[52,2111,96],{"class":58},[52,2113,434],{"class":69},[52,2115,173],{"class":108},[52,2117,1026],{"class":69},[52,2119,2120],{"class":179},"\u002F\u002F 已处理：模拟失败\n",[15,2122,2123,2124,2127],{},"await 的拒绝若没有在函数内部捕获，会中断后续执行并让整个 async 函数拒绝；被 catch 处理后则可继续。彼此独立的任务可以先启动再 ",[22,2125,2126],{},"await Promise.all(...)","，有数据依赖的任务按顺序 await。",[31,2129,2130],{"id":2130},"网络请求工具",[15,2132,2133,2134,269],{},"课程列出 jQuery Ajax、Fetch 和 Axios。Fetch 是宿主环境提供的 Web API，不是 ES6 语言内置特性；Axios、jQuery 是第三方库。真实请求需要处理失败、超时和响应状态，代理场景见 ",[263,2135,2137],{"href":2136},"\u002Fdocs\u002Fwebpack-basics","Webpack 开发服务器",[31,2139,2140],{"id":2140},"来源记录",[2142,2143,2144,2157,2166,2175],"ul",{},[2145,2146,2147,491,2150,491,2153,2156],"li",{},[22,2148,2149],{},"003_es6\u002Fcode\u002F02_promise.js",[22,2151,2152],{},"03_promise.js",[22,2154,2155],{},"04_promise.js","：回调封装、Promise 链和组合方法，替换原外部接口。",[2145,2158,2159,491,2162,2165],{},[22,2160,2161],{},"003_es6\u002Fcode\u002F05_generator.js",[22,2163,2164],{},"06_async.js","：迭代器、co 与自动执行流程。",[2145,2167,2168,491,2171,2174],{},[22,2169,2170],{},"004_es6\u002Fcode\u002F01_async.js",[22,2172,2173],{},"006_webpack\u002Fcode\u002F01_gulp\u002Fes6\u002F01_async.js","：等待结果与错误传播，同内容合并。",[2145,2176,2177,491,2180,2183],{},[22,2178,2179],{},"003_es6\u002Fcode\u002Freadme.md",[22,2181,2182],{},"004_es6\u002Fcode\u002Freadme.md"," 的异步章节：去重复习，保留独有知识点。",[2185,2186,2187],"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":48,"searchDepth":102,"depth":102,"links":2189},[2190,2193,2194,2195,2196,2199,2202,2203],{"id":33,"depth":73,"text":34,"children":2191},[2192],{"id":273,"depth":102,"text":273},{"id":498,"depth":73,"text":499},{"id":809,"depth":73,"text":810},{"id":1037,"depth":73,"text":1038},{"id":1405,"depth":73,"text":1406,"children":2197},[2198],{"id":1555,"depth":102,"text":1556},{"id":1876,"depth":73,"text":1877,"children":2200},[2201],{"id":2003,"depth":102,"text":2003},{"id":2130,"depth":73,"text":2130},{"id":2140,"depth":73,"text":2140},"fundamentals","2026-09-09","从回调到 Promise 链、组合方法、Generator 执行与 async 错误处理的课程示例整理。",false,"md",{},"\u002Fdocs\u002Fjs-promise-async",{"title":5,"description":2206},"尚学堂 ES6 课程 003_es6、004_es6 学习笔记与代码","docs\u002Fjs-promise-async",[2215,2216,2217],"javascript","es6","notes","lIa3oXUUUro2L_O_2LynO0hNvkzyaCEHW2--gKxJG3k",[2220,2227,2232,2237,2239,2248,2259,2266,2272,2282,2289,2298,2303,2310,2315,2321,2327,2334,2341,2348,2357,2363,2369,2375,2380,2385,2390,2394],{"path":2221,"title":2222,"description":2223,"date":2205,"category":2224,"tags":2225},"\u002Fdocs\u002Fbabel-basics","Babel 转译基础与构建集成","Babel 7 的 CLI、preset、plugin、目标环境以及 Gulp、Webpack 和 JSX 转译配置摘录。","toolchain",[2215,2216,2226,2217],"webpack",{"path":2228,"title":2229,"description":2230,"date":2205,"category":2204,"tags":2231},"\u002Fdocs\u002Fes6-arrays-objects","ES6 数组与对象扩展","展开运算符、Array.from、Object.assign、属性描述符与图片预加载示例。",[2215,2216,2217],{"path":2233,"title":2234,"description":2235,"date":2205,"category":2204,"tags":2236},"\u002Fdocs\u002Fes6-basics","ES6 基础：作用域、解构与模板字符串","从课程示例整理 let、const、暂时性死区、全局对象、数组与对象解构及模板字符串。",[2215,2216,2217],{"path":2210,"title":5,"description":2206,"date":2205,"category":2204,"tags":2238},[2215,2216,2217],{"path":2240,"title":2241,"description":2242,"date":2243,"category":2224,"tags":2244},"\u002Fdocs\u002Flinux-commands-cheatsheet","Linux 常用命令与权限管理速查","cp\u002Fmv\u002Frm、目录导航、查找、压缩、网络等基础命令速查，以及 chmod\u002Fchown 的数字与符号写法、常用组合和 WSL 下的坑。","2026-05-28",[2245,2246,2247],"linux","wsl2","cheatsheet",{"path":2249,"title":2250,"description":2251,"date":2252,"category":2253,"tags":2254},"\u002Fdocs\u002Ffrontend-coding-standards","前端团队编码规范","HTML \u002F CSS \u002F JavaScript 三端统一的团队编码约定，含缩进、命名、语法与禁用项，可直接作为 Code Review 依据。","2025-12-17","standards",[2255,2256,2215,2216,2257,2258],"html","css","best-practice","guide",{"path":2260,"title":2261,"description":2262,"date":2263,"category":2224,"tags":2264},"\u002Fdocs\u002Fwindows-mklink","Windows mklink 符号链接用法","mklink 各参数区别与实用场景：目录联接、符号链接与硬链接的选择。","2024-12-18",[2265,2247],"windows",{"path":2267,"title":2268,"description":2269,"date":2270,"category":2224,"tags":2271},"\u002Fdocs\u002Frandom-color-utils","JS 随机颜色生成方法","几种生成随机 RGB \u002F HEX 颜色的实现方式与各自适用场景。","2024-12-11",[2215,2247],{"path":2273,"title":2274,"description":2275,"date":2276,"category":2277,"tags":2278},"\u002Fdocs\u002Fcanvas-vs-svg","Canvas 与 SVG 绘图方案选型","对比 Canvas 与 SVG 两种绘图方案的优缺点与适用场景，给出选型判断依据。","2024-12-09","visualization",[2279,2280,2281,2257],"canvas","svg","performance",{"path":2283,"title":2284,"description":2285,"date":2286,"category":2224,"tags":2287},"\u002Fdocs\u002Ffree-commercial-fonts","免费可商用字体整理","整理思源黑体、思源宋体等可商用中文字体，规避字体版权风险。","2024-11-03",[2288,2256,2217],"font",{"path":2290,"title":2291,"description":2292,"date":2286,"category":2293,"tags":2294},"\u002Fdocs\u002Finterview-browser-network","浏览器与网络考点","从输入 URL 到页面呈现的完整链路，涵盖渲染流程、回流重绘、HTTP 报文与状态码、跨域同源策略与常见攻击方式。","interview",[2295,2296,2297,2281,2217],"browser","http","network",{"path":2299,"title":2300,"description":2301,"date":2286,"category":2293,"tags":2302},"\u002Fdocs\u002Finterview-css-layout","CSS 与布局考点","em 与 rem 的区别、移动端三种适配方案对比、viewport 标准设置与 REM 布局的媒体查询实现。",[2256,2255,2257,2217],{"path":2304,"title":2305,"description":2306,"date":2286,"category":2293,"tags":2307},"\u002Fdocs\u002Finterview-framework-tooling","框架与工程化考点","React diff 与 setState 机制、Redux 核心组成、Vue 常考清单，以及 Webpack、Vite、Git 的面试要点。",[2308,2215,2226,2309,2217],"vue","vite",{"path":2311,"title":2312,"description":2313,"date":2286,"category":2293,"tags":2314},"\u002Fdocs\u002Finterview-javascript-core","JavaScript 核心考点","数据类型、this 绑定、闭包、原型链、异步与数组方法，前端面试中 JS 部分的高频考点与代码示例。",[2215,2216,2217],{"path":2316,"title":2317,"description":2318,"date":2286,"category":2204,"tags":2319},"\u002Fdocs\u002Fjs-module-systems","JavaScript 模块化方案","梳理 CommonJS、AMD、ES Module 等模块化方案的差异与使用方式。",[2215,2320,2216,2217],"module-system",{"path":2322,"title":2323,"description":2324,"date":2286,"category":2204,"tags":2325},"\u002Fdocs\u002Fwebsocket-basics","WebSocket 基础","WebSocket 全双工通信协议的事件、方法与基本用法整理。",[2326,2297,2215,2217],"websocket",{"path":2328,"title":2329,"description":2330,"date":2331,"category":2224,"tags":2332},"\u002Fdocs\u002Fmarkdown-syntax","Markdown 语法速查","Markdown 标题、强调、列表、区块引用、代码、表格、转义与 Mermaid 图表语法整理。","2024-10-18",[2333,2247,2217],"markdown",{"path":2335,"title":2336,"description":2337,"date":2338,"category":2277,"tags":2339},"\u002Fdocs\u002Fgojs-getting-started","GoJS 入门实战","从引入方式、画布初始化到节点模板与数据绑定，一份可直接上手的 GoJS 流程图开发笔记。","2024-08-22",[2340,2215,2217],"gojs",{"path":2342,"title":2343,"description":2344,"date":2345,"category":2277,"tags":2346},"\u002Fdocs\u002Fecharts-options-notes","ECharts 配置项速查","整理 ECharts 常用 option 配置：数据格式、坐标轴、图例与交互项的实际用法。","2024-08-09",[2347,2215,2247],"echarts",{"path":2349,"title":2350,"description":2351,"date":2352,"category":2224,"tags":2353},"\u002Fdocs\u002Fyarn-npm-install-errors","yarn \u002F npm 安装报错处理","yarn 引擎版本不兼容时的 ignore-engines 绕过、Windows 刷新 DNS 解析缓存、npm 缓存清理与校验。","2024-08-06",[2354,2355,2265,2356],"npm","nodejs","troubleshooting",{"path":2358,"title":2359,"description":2360,"date":2361,"category":2277,"tags":2362},"\u002Fdocs\u002Fgojs-grid-panel","GoJS 网格面板用法","Diagram.grid 默认网格与网格捕捉、单元格尺寸定制，用 LineH\u002FLineV\u002FBarH\u002FBarV 自定义网格样式，以及把 Grid 面板当作节点元素使用。","2024-07-01",[2340,2215,2217],{"path":2364,"title":2365,"description":2366,"date":2367,"category":2204,"tags":2368},"\u002Fdocs\u002Fhttp-status-codes","HTTP 响应状态码详解","按 1xx 到 5xx 分类梳理 HTTP 状态码的含义与典型使用场景。","2024-06-27",[2296,2297,2247],{"path":2370,"title":2371,"description":2372,"date":2373,"category":2204,"tags":2374},"\u002Fdocs\u002Fes6-functions-classes","ES6 函数与 Class","默认参数、rest、箭头函数的 this、Class 方法、访问器、静态成员与继承。","2023-04-26",[2215,2216,2217],{"path":2376,"title":2377,"description":2378,"date":2373,"category":2224,"tags":2379},"\u002Fdocs\u002Fgulp-basics","Gulp 4 任务与文件流","Gulp 任务完成信号、串并行组合、文件流、资源处理、分阶段输出和文件监听。",[2215,2355,2217],{"path":2381,"title":2382,"description":2383,"date":2373,"category":2204,"tags":2384},"\u002Fdocs\u002Fjs-proxy-reflect","Proxy 与 Reflect 入门","通过属性读取和赋值示例理解 Proxy、Reflect、receiver 与拦截限制。",[2215,2216,2217],{"path":2386,"title":2387,"description":2388,"date":2373,"category":2224,"tags":2389},"\u002Fdocs\u002Fless-basics","Less 语法与编译笔记","变量、嵌套、混合、extend、导入、内置函数和递归生成列的课程示例。",[2256,2217,2247],{"path":2136,"title":2391,"description":2392,"date":2373,"category":2224,"tags":2393},"Webpack 4 配置与开发服务器笔记","课程中的入口出口、loader、plugin、source map、开发代理以及 React 环境配置片段。",[2226,2215,2355,2217],{"path":2395,"title":2396,"description":2397,"date":2398,"category":2204,"tags":2399},"\u002Fdocs\u002Fhtml-basics","HTML 基础笔记","HTML 语法规范、常用标签、表格、表单、Canvas 入门与 JavaScript 输出方式速查。","2022-06-10",[2255,2217,2247],1789635934133]