[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fevent-loop":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fevent-loop":2240,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fevent-loop":2266},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":14,"pinned":15,"draft":15,"body":16,"seo":2236,"stem":2237,"id":2238,"extension":2239},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fevent-loop","异步编程与事件循环","JavaScript 在单线程上通过事件循环调度异步任务。前置：语言基础。","技能小册",[12,13],"javascript","event-loop","2020-03-23",false,{"type":17,"value":18,"toc":2203},"minimark",[19,22,37,42,45,50,56,95,109,119,123,138,299,303,314,318,322,325,443,447,458,554,558,588,592,605,609,615,619,641,645,770,774,799,866,879,883,892,896,900,918,1183,1187,1207,1384,1388,1399,1403,1425,1429,1654,1658,1670,1674,1687,1757,1761,1769,2018,2022,2050,2053,2117,2120,2123,2126,2199],[20,21,8],"h1",{"id":8},[23,24,25,26,30,31,36],"p",{},"JavaScript 在单线程上通过",[27,28,29],"strong",{},"事件循环","调度异步任务。前置：",[32,33,35],"a",{"href":34},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fbasics","语言基础","。",[38,39,41],"h2",{"id":40},"一事件循环event-loop","一、事件循环（Event Loop）",[23,43,44],{},"JavaScript 是单线程的，事件循环是其实现异步非阻塞 I\u002FO 的核心机制。",[46,47,49],"h3",{"id":48},"_1-宏任务macrotask与微任务microtask","1. 宏任务（MacroTask）与微任务（MicroTask）",[23,51,52,55],{},[27,53,54],{},"浏览器","（HTML 规范中的 task）常见划分：",[57,58,59,79],"ul",{},[60,61,62,65,66,70,71,74,75,78],"li",{},[27,63,64],{},"宏任务（task）","：",[67,68,69],"code",{},"setTimeout"," \u002F ",[67,72,73],{},"setInterval","、",[67,76,77],{},"MessageChannel","、I\u002FO 回调、用户事件等。",[60,80,81,65,84,87,88,74,91,94],{},[27,82,83],{},"微任务（microtask）",[67,85,86],{},"Promise"," 回调、",[67,89,90],{},"queueMicrotask()",[67,92,93],{},"MutationObserver"," 等。",[23,96,97,100,101,104,105,108],{},[27,98,99],{},"Node.js"," 另有 ",[67,102,103],{},"process.nextTick","（在当前阶段之后、微任务之前执行）与 ",[67,106,107],{},"setImmediate","（check 阶段），与浏览器队列细节不同，勿混为一谈。",[23,110,111,114,115,118],{},[67,112,113],{},"requestAnimationFrame"," 在浏览器中用于下一帧绘制前回调，",[27,116,117],{},"不属于","上述微任务队列，通常在本轮微任务清空后、渲染前执行。",[46,120,122],{"id":121},"_2-执行顺序","2. 执行顺序",[124,125,126,129,132,135],"ol",{},[60,127,128],{},"执行一个宏任务（从宏任务队列中取出）",[60,130,131],{},"执行当前宏任务关联的所有微任务（清空微任务队列）",[60,133,134],{},"必要时进行 UI 渲染（浏览器）",[60,136,137],{},"进入下一轮循环，执行下一个宏任务",[139,140,145],"pre",{"className":141,"code":142,"language":143,"meta":144,"style":144},"language-js shiki shiki-themes material-theme-lighter github-light github-dark","console.log(\"1\");\nsetTimeout(() => console.log(\"2\"), 0);\nPromise.resolve().then(() => console.log(\"3\"));\nconsole.log(\"4\");\n\u002F\u002F 输出: 1, 4, 3, 2\n","js","",[67,146,147,183,226,270,292],{"__ignoreMap":144},[148,149,152,156,160,164,167,171,175,177,180],"span",{"class":150,"line":151},"line",1,[148,153,155],{"class":154},"su5hD","console",[148,157,159],{"class":158},"sP7_E",".",[148,161,163],{"class":162},"sGLFI","log",[148,165,166],{"class":154},"(",[148,168,170],{"class":169},"sjJ54","\"",[148,172,174],{"class":173},"s_sjI","1",[148,176,170],{"class":169},[148,178,179],{"class":154},")",[148,181,182],{"class":158},";\n",[148,184,186,188,190,193,197,200,202,204,206,208,211,213,215,218,222,224],{"class":150,"line":185},2,[148,187,69],{"class":162},[148,189,166],{"class":154},[148,191,192],{"class":158},"()",[148,194,196],{"class":195},"sbsja"," =>",[148,198,199],{"class":154}," console",[148,201,159],{"class":158},[148,203,163],{"class":162},[148,205,166],{"class":154},[148,207,170],{"class":169},[148,209,210],{"class":173},"2",[148,212,170],{"class":169},[148,214,179],{"class":154},[148,216,217],{"class":158},",",[148,219,221],{"class":220},"srdBf"," 0",[148,223,179],{"class":154},[148,225,182],{"class":158},[148,227,229,232,234,237,239,241,244,246,248,250,252,254,256,258,260,263,265,268],{"class":150,"line":228},3,[148,230,86],{"class":231},"sZMiF",[148,233,159],{"class":158},[148,235,236],{"class":162},"resolve",[148,238,192],{"class":154},[148,240,159],{"class":158},[148,242,243],{"class":162},"then",[148,245,166],{"class":154},[148,247,192],{"class":158},[148,249,196],{"class":195},[148,251,199],{"class":154},[148,253,159],{"class":158},[148,255,163],{"class":162},[148,257,166],{"class":154},[148,259,170],{"class":169},[148,261,262],{"class":173},"3",[148,264,170],{"class":169},[148,266,267],{"class":154},"))",[148,269,182],{"class":158},[148,271,273,275,277,279,281,283,286,288,290],{"class":150,"line":272},4,[148,274,155],{"class":154},[148,276,159],{"class":158},[148,278,163],{"class":162},[148,280,166],{"class":154},[148,282,170],{"class":169},[148,284,285],{"class":173},"4",[148,287,170],{"class":169},[148,289,179],{"class":154},[148,291,182],{"class":158},[148,293,295],{"class":150,"line":294},5,[148,296,298],{"class":297},"sutJx","\u002F\u002F 输出: 1, 4, 3, 2\n",[46,300,302],{"id":301},"_3-常见误区","3. 常见误区",[57,304,305,311],{},[60,306,307,310],{},[67,308,309],{},"setTimeout(fn, 0)"," 并不立即执行，它需要等待当前宏任务和微任务全部完成。",[60,312,313],{},"微任务中可以继续添加微任务，会一直执行直到微任务队列为空（可能导致“卡死”）。",[38,315,317],{"id":316},"二回调地狱与解救","二、回调地狱与解救",[46,319,321],{"id":320},"_1-回调地狱callback-hell","1. 回调地狱（Callback Hell）",[23,323,324],{},"多个异步操作层层嵌套，导致代码难以阅读和维护。",[139,326,328],{"className":141,"code":327,"language":143,"meta":144,"style":144},"getData(function (a) {\n    getMoreData(a, function (b) {\n        getMoreMoreData(b, function (c) {\n            console.log(c);\n        });\n    });\n});\n",[67,329,330,351,375,397,414,423,433],{"__ignoreMap":144},[148,331,332,335,337,340,343,346,348],{"class":150,"line":151},[148,333,334],{"class":162},"getData",[148,336,166],{"class":154},[148,338,339],{"class":195},"function",[148,341,342],{"class":158}," (",[148,344,32],{"class":345},"s99_P",[148,347,179],{"class":158},[148,349,350],{"class":158}," {\n",[148,352,353,356,359,361,363,366,368,371,373],{"class":150,"line":185},[148,354,355],{"class":162},"    getMoreData",[148,357,166],{"class":358},"skxfh",[148,360,32],{"class":154},[148,362,217],{"class":158},[148,364,365],{"class":195}," function",[148,367,342],{"class":158},[148,369,370],{"class":345},"b",[148,372,179],{"class":158},[148,374,350],{"class":158},[148,376,377,380,382,384,386,388,390,393,395],{"class":150,"line":228},[148,378,379],{"class":162},"        getMoreMoreData",[148,381,166],{"class":358},[148,383,370],{"class":154},[148,385,217],{"class":158},[148,387,365],{"class":195},[148,389,342],{"class":158},[148,391,392],{"class":345},"c",[148,394,179],{"class":158},[148,396,350],{"class":158},[148,398,399,402,404,406,408,410,412],{"class":150,"line":272},[148,400,401],{"class":154},"            console",[148,403,159],{"class":158},[148,405,163],{"class":162},[148,407,166],{"class":358},[148,409,392],{"class":154},[148,411,179],{"class":358},[148,413,182],{"class":158},[148,415,416,419,421],{"class":150,"line":294},[148,417,418],{"class":158},"        }",[148,420,179],{"class":358},[148,422,182],{"class":158},[148,424,426,429,431],{"class":150,"line":425},6,[148,427,428],{"class":158},"    }",[148,430,179],{"class":358},[148,432,182],{"class":158},[148,434,436,439,441],{"class":150,"line":435},7,[148,437,438],{"class":158},"}",[148,440,179],{"class":154},[148,442,182],{"class":158},[46,444,446],{"id":445},"_2-promise-链式调用","2. Promise 链式调用",[23,448,449,450,453,454,457],{},"Promise 是一个代表异步操作最终完成（或失败）的对象。通过 ",[67,451,452],{},".then()"," 和 ",[67,455,456],{},".catch()"," 实现链式调用，避免嵌套。",[139,459,461],{"className":141,"code":460,"language":143,"meta":144,"style":144},"getData()\n    .then(a => getMoreData(a))\n    .then(b => getMoreMoreData(b))\n    .then(c => console.log(c))\n    .catch(err => console.error(err));\n",[67,462,463,470,489,507,528],{"__ignoreMap":144},[148,464,465,467],{"class":150,"line":151},[148,466,334],{"class":162},[148,468,469],{"class":154},"()\n",[148,471,472,475,477,479,481,483,486],{"class":150,"line":185},[148,473,474],{"class":158},"    .",[148,476,243],{"class":162},[148,478,166],{"class":154},[148,480,32],{"class":345},[148,482,196],{"class":195},[148,484,485],{"class":162}," getMoreData",[148,487,488],{"class":154},"(a))\n",[148,490,491,493,495,497,499,501,504],{"class":150,"line":228},[148,492,474],{"class":158},[148,494,243],{"class":162},[148,496,166],{"class":154},[148,498,370],{"class":345},[148,500,196],{"class":195},[148,502,503],{"class":162}," getMoreMoreData",[148,505,506],{"class":154},"(b))\n",[148,508,509,511,513,515,517,519,521,523,525],{"class":150,"line":272},[148,510,474],{"class":158},[148,512,243],{"class":162},[148,514,166],{"class":154},[148,516,392],{"class":345},[148,518,196],{"class":195},[148,520,199],{"class":154},[148,522,159],{"class":158},[148,524,163],{"class":162},[148,526,527],{"class":154},"(c))\n",[148,529,530,532,535,537,540,542,544,546,549,552],{"class":150,"line":294},[148,531,474],{"class":158},[148,533,534],{"class":162},"catch",[148,536,166],{"class":154},[148,538,539],{"class":345},"err",[148,541,196],{"class":195},[148,543,199],{"class":154},[148,545,159],{"class":158},[148,547,548],{"class":162},"error",[148,550,551],{"class":154},"(err))",[148,553,182],{"class":158},[46,555,557],{"id":556},"_3-promise-静态方法","3. Promise 静态方法",[57,559,560,566,572,582],{},[60,561,562,565],{},[67,563,564],{},"Promise.all(iterable)","：所有成功才成功，任一失败立即失败（返回失败原因）。",[60,567,568,571],{},[67,569,570],{},"Promise.allSettled(iterable)","：等待所有完成（无论成功或失败），返回每个结果的状态和值。",[60,573,574,577,578,581],{},[67,575,576],{},"Promise.any(iterable)","：任意一个成功即成功，全部失败才失败（返回 ",[67,579,580],{},"AggregateError","）。",[60,583,584,587],{},[67,585,586],{},"Promise.race(iterable)","：返回最先敲定（成功或失败）的结果。",[46,589,591],{"id":590},"_4-错误冒泡","4. 错误冒泡",[23,593,594,595,597,598,600,601,604],{},"在 Promise 链中，",[67,596,534],{}," 可以捕获链条中任意位置抛出的错误（同步或异步）。若没有 ",[67,599,534],{},"，错误会被静默吞没（现代浏览器\u002FNode.js 会触发 ",[67,602,603],{},"unhandledrejection"," 事件）。",[38,606,608],{"id":607},"三asyncawait","三、async\u002Fawait",[23,610,611,614],{},[67,612,613],{},"async\u002Fawait"," 是 Promise 的语法糖，使异步代码看起来像同步代码，更易于阅读和调试。",[46,616,618],{"id":617},"_1-原理生成器generator-自动执行器","1. 原理：生成器（Generator）+ 自动执行器",[23,620,621,624,625,628,629,632,633,636,637,640],{},[67,622,623],{},"async"," 函数内部会被编译成一个生成器函数（Generator），配合类似 ",[67,626,627],{},"co"," 库的自动执行器，每次 ",[67,630,631],{},"await"," 对应一次 ",[67,634,635],{},"yield","，自动处理 ",[67,638,639],{},"next()"," 调用和 Promise 解析。",[46,642,644],{"id":643},"_2-基本用法","2. 基本用法",[139,646,648],{"className":141,"code":647,"language":143,"meta":144,"style":144},"async function fetchData() {\n    try {\n        const a = await getData();\n        const b = await getMoreData(a);\n        return b;\n    } catch (err) {\n        console.error(err);\n    }\n}\n",[67,649,650,663,671,694,715,724,741,758,764],{"__ignoreMap":144},[148,651,652,654,656,659,661],{"class":150,"line":151},[148,653,623],{"class":195},[148,655,365],{"class":195},[148,657,658],{"class":162}," fetchData",[148,660,192],{"class":158},[148,662,350],{"class":158},[148,664,665,669],{"class":150,"line":185},[148,666,668],{"class":667},"sVHd0","    try",[148,670,350],{"class":158},[148,672,673,676,680,684,687,690,692],{"class":150,"line":228},[148,674,675],{"class":195},"        const",[148,677,679],{"class":678},"s_hVV"," a",[148,681,683],{"class":682},"smGrS"," =",[148,685,686],{"class":667}," await",[148,688,689],{"class":162}," getData",[148,691,192],{"class":358},[148,693,182],{"class":158},[148,695,696,698,701,703,705,707,709,711,713],{"class":150,"line":272},[148,697,675],{"class":195},[148,699,700],{"class":678}," b",[148,702,683],{"class":682},[148,704,686],{"class":667},[148,706,485],{"class":162},[148,708,166],{"class":358},[148,710,32],{"class":154},[148,712,179],{"class":358},[148,714,182],{"class":158},[148,716,717,720,722],{"class":150,"line":294},[148,718,719],{"class":667},"        return",[148,721,700],{"class":154},[148,723,182],{"class":158},[148,725,726,728,731,733,735,738],{"class":150,"line":425},[148,727,428],{"class":158},[148,729,730],{"class":667}," catch",[148,732,342],{"class":358},[148,734,539],{"class":154},[148,736,737],{"class":358},") ",[148,739,740],{"class":158},"{\n",[148,742,743,746,748,750,752,754,756],{"class":150,"line":435},[148,744,745],{"class":154},"        console",[148,747,159],{"class":158},[148,749,548],{"class":162},[148,751,166],{"class":358},[148,753,539],{"class":154},[148,755,179],{"class":358},[148,757,182],{"class":158},[148,759,761],{"class":150,"line":760},8,[148,762,763],{"class":158},"    }\n",[148,765,767],{"class":150,"line":766},9,[148,768,769],{"class":158},"}\n",[46,771,773],{"id":772},"_3-错误处理","3. 错误处理",[57,775,776,787],{},[60,777,778,783,784,786],{},[27,779,780],{},[67,781,782],{},"try\u002Fcatch","：可以捕获 ",[67,785,631],{}," 抛出的 rejected Promise，也捕获同步错误。",[60,788,789,793,794,796,797,36],{},[27,790,791],{},[67,792,456],{},"：在 ",[67,795,631],{}," 后直接链式调用 ",[67,798,456],{},[139,800,802],{"className":141,"code":801,"language":143,"meta":144,"style":144},"const data = await fetch(url)\n    .then(res => res.json())\n    .catch(err => null);\n",[67,803,804,822,846],{"__ignoreMap":144},[148,805,806,809,812,814,816,819],{"class":150,"line":151},[148,807,808],{"class":195},"const",[148,810,811],{"class":678}," data",[148,813,683],{"class":682},[148,815,686],{"class":667},[148,817,818],{"class":162}," fetch",[148,820,821],{"class":154},"(url)\n",[148,823,824,826,828,830,833,835,838,840,843],{"class":150,"line":185},[148,825,474],{"class":158},[148,827,243],{"class":162},[148,829,166],{"class":154},[148,831,832],{"class":345},"res",[148,834,196],{"class":195},[148,836,837],{"class":154}," res",[148,839,159],{"class":158},[148,841,842],{"class":162},"json",[148,844,845],{"class":154},"())\n",[148,847,848,850,852,854,856,858,862,864],{"class":150,"line":228},[148,849,474],{"class":158},[148,851,534],{"class":162},[148,853,166],{"class":154},[148,855,539],{"class":345},[148,857,196],{"class":195},[148,859,861],{"class":860},"s39Yj"," null",[148,863,179],{"class":154},[148,865,182],{"class":158},[23,867,868,869,871,872,875,876,36],{},"注意：",[67,870,623],{}," 函数总是返回一个 Promise，如果函数内没有 ",[67,873,874],{},"return","，则返回 ",[67,877,878],{},"Promise.resolve(undefined)",[46,880,882],{"id":881},"_4-顶层-awaites2022","4. 顶层 await（ES2022）",[23,884,885,886,888,889,891],{},"在模块中可以直接使用 ",[67,887,631],{}," 而不需要包裹 ",[67,890,623],{}," 函数，适用于模块初始化依赖异步操作。",[38,893,895],{"id":894},"四异步迭代器for-awaitof与异步生成器","四、异步迭代器（for await...of）与异步生成器",[46,897,899],{"id":898},"_1-异步迭代器async-iterator","1. 异步迭代器（Async Iterator）",[23,901,902,903,906,907,909,910,913,914,917],{},"一个对象实现了 ",[67,904,905],{},"Symbol.asyncIterator"," 方法，该方法返回一个对象，其 ",[67,908,639],{}," 方法返回 ",[67,911,912],{},"Promise\u003C{value, done}>","。可以使用 ",[67,915,916],{},"for await...of"," 循环消费。",[139,919,921],{"className":141,"code":920,"language":143,"meta":144,"style":144},"const asyncIterable = {\n    [Symbol.asyncIterator]() {\n        let i = 0;\n        return {\n            next() {\n                if (i \u003C 3) {\n                    return Promise.resolve({ value: i++, done: false });\n                }\n                return Promise.resolve({ done: true });\n            },\n        };\n    },\n};\n\n(async () => {\n    for await (const num of asyncIterable) {\n        console.log(num); \u002F\u002F 0,1,2\n    }\n})();\n",[67,922,923,934,948,962,968,978,998,1044,1049,1077,1083,1089,1095,1101,1108,1122,1146,1168,1173],{"__ignoreMap":144},[148,924,925,927,930,932],{"class":150,"line":151},[148,926,808],{"class":195},[148,928,929],{"class":678}," asyncIterable",[148,931,683],{"class":682},[148,933,350],{"class":158},[148,935,936,939,941,944,946],{"class":150,"line":185},[148,937,938],{"class":154},"    [Symbol",[148,940,159],{"class":158},[148,942,943],{"class":154},"asyncIterator]",[148,945,192],{"class":158},[148,947,350],{"class":158},[148,949,950,953,956,958,960],{"class":150,"line":228},[148,951,952],{"class":195},"        let",[148,954,955],{"class":154}," i",[148,957,683],{"class":682},[148,959,221],{"class":220},[148,961,182],{"class":158},[148,963,964,966],{"class":150,"line":272},[148,965,719],{"class":667},[148,967,350],{"class":158},[148,969,970,974,976],{"class":150,"line":294},[148,971,973],{"class":972},"sVXei","            next",[148,975,192],{"class":158},[148,977,350],{"class":158},[148,979,980,983,985,988,991,994,996],{"class":150,"line":425},[148,981,982],{"class":667},"                if",[148,984,342],{"class":358},[148,986,987],{"class":154},"i",[148,989,990],{"class":682}," \u003C",[148,992,993],{"class":220}," 3",[148,995,737],{"class":358},[148,997,740],{"class":158},[148,999,1000,1003,1006,1008,1010,1012,1015,1018,1021,1023,1026,1028,1031,1033,1037,1040,1042],{"class":150,"line":435},[148,1001,1002],{"class":667},"                    return",[148,1004,1005],{"class":231}," Promise",[148,1007,159],{"class":158},[148,1009,236],{"class":162},[148,1011,166],{"class":358},[148,1013,1014],{"class":158},"{",[148,1016,1017],{"class":358}," value",[148,1019,1020],{"class":158},":",[148,1022,955],{"class":154},[148,1024,1025],{"class":682},"++",[148,1027,217],{"class":158},[148,1029,1030],{"class":358}," done",[148,1032,1020],{"class":158},[148,1034,1036],{"class":1035},"syTEX"," false",[148,1038,1039],{"class":158}," }",[148,1041,179],{"class":358},[148,1043,182],{"class":158},[148,1045,1046],{"class":150,"line":760},[148,1047,1048],{"class":158},"                }\n",[148,1050,1051,1054,1056,1058,1060,1062,1064,1066,1068,1071,1073,1075],{"class":150,"line":766},[148,1052,1053],{"class":667},"                return",[148,1055,1005],{"class":231},[148,1057,159],{"class":158},[148,1059,236],{"class":162},[148,1061,166],{"class":358},[148,1063,1014],{"class":158},[148,1065,1030],{"class":358},[148,1067,1020],{"class":158},[148,1069,1070],{"class":1035}," true",[148,1072,1039],{"class":158},[148,1074,179],{"class":358},[148,1076,182],{"class":158},[148,1078,1080],{"class":150,"line":1079},10,[148,1081,1082],{"class":158},"            },\n",[148,1084,1086],{"class":150,"line":1085},11,[148,1087,1088],{"class":158},"        };\n",[148,1090,1092],{"class":150,"line":1091},12,[148,1093,1094],{"class":158},"    },\n",[148,1096,1098],{"class":150,"line":1097},13,[148,1099,1100],{"class":158},"};\n",[148,1102,1104],{"class":150,"line":1103},14,[148,1105,1107],{"emptyLinePlaceholder":1106},true,"\n",[148,1109,1111,1113,1115,1118,1120],{"class":150,"line":1110},15,[148,1112,166],{"class":154},[148,1114,623],{"class":195},[148,1116,1117],{"class":158}," ()",[148,1119,196],{"class":195},[148,1121,350],{"class":158},[148,1123,1125,1128,1130,1132,1134,1137,1140,1142,1144],{"class":150,"line":1124},16,[148,1126,1127],{"class":667},"    for",[148,1129,686],{"class":667},[148,1131,342],{"class":358},[148,1133,808],{"class":195},[148,1135,1136],{"class":678}," num",[148,1138,1139],{"class":682}," of",[148,1141,929],{"class":154},[148,1143,737],{"class":358},[148,1145,740],{"class":158},[148,1147,1149,1151,1153,1155,1157,1160,1162,1165],{"class":150,"line":1148},17,[148,1150,745],{"class":154},[148,1152,159],{"class":158},[148,1154,163],{"class":162},[148,1156,166],{"class":358},[148,1158,1159],{"class":154},"num",[148,1161,179],{"class":358},[148,1163,1164],{"class":158},";",[148,1166,1167],{"class":297}," \u002F\u002F 0,1,2\n",[148,1169,1171],{"class":150,"line":1170},18,[148,1172,763],{"class":158},[148,1174,1176,1178,1181],{"class":150,"line":1175},19,[148,1177,438],{"class":158},[148,1179,1180],{"class":154},")()",[148,1182,182],{"class":158},[46,1184,1186],{"id":1185},"_2-异步生成器async-generator","2. 异步生成器（Async Generator）",[23,1188,1189,1190,1193,1194,1197,1198,1200,1201,1203,1204,1206],{},"使用 ",[67,1191,1192],{},"async function*"," 定义，可以 ",[67,1195,1196],{},"yield Promise"," 或直接 ",[67,1199,635],{}," 值，",[67,1202,916],{}," 会自动等待每个 ",[67,1205,635],{}," 的 Promise 解析。",[139,1208,1210],{"className":141,"code":1209,"language":143,"meta":144,"style":144},"async function* generateSequence() {\n    for (let i = 0; i \u003C 3; i++) {\n        await new Promise(r => setTimeout(r, 100)); \u002F\u002F 模拟异步\n        yield i;\n    }\n}\n\n(async () => {\n    for await (const val of generateSequence()) {\n        console.log(val); \u002F\u002F 0,1,2 (每个间隔 100ms)\n    }\n})();\n",[67,1211,1212,1228,1261,1297,1306,1310,1314,1318,1330,1352,1372,1376],{"__ignoreMap":144},[148,1213,1214,1216,1218,1221,1224,1226],{"class":150,"line":151},[148,1215,623],{"class":195},[148,1217,365],{"class":195},[148,1219,1220],{"class":682},"*",[148,1222,1223],{"class":162}," generateSequence",[148,1225,192],{"class":158},[148,1227,350],{"class":158},[148,1229,1230,1232,1234,1237,1239,1241,1243,1245,1247,1249,1251,1253,1255,1257,1259],{"class":150,"line":185},[148,1231,1127],{"class":667},[148,1233,342],{"class":358},[148,1235,1236],{"class":195},"let",[148,1238,955],{"class":154},[148,1240,683],{"class":682},[148,1242,221],{"class":220},[148,1244,1164],{"class":158},[148,1246,955],{"class":154},[148,1248,990],{"class":682},[148,1250,993],{"class":220},[148,1252,1164],{"class":158},[148,1254,955],{"class":154},[148,1256,1025],{"class":682},[148,1258,737],{"class":358},[148,1260,740],{"class":158},[148,1262,1263,1266,1269,1271,1273,1276,1278,1281,1283,1285,1287,1290,1292,1294],{"class":150,"line":228},[148,1264,1265],{"class":667},"        await",[148,1267,1268],{"class":682}," new",[148,1270,1005],{"class":231},[148,1272,166],{"class":358},[148,1274,1275],{"class":345},"r",[148,1277,196],{"class":195},[148,1279,1280],{"class":162}," setTimeout",[148,1282,166],{"class":358},[148,1284,1275],{"class":154},[148,1286,217],{"class":158},[148,1288,1289],{"class":220}," 100",[148,1291,267],{"class":358},[148,1293,1164],{"class":158},[148,1295,1296],{"class":297}," \u002F\u002F 模拟异步\n",[148,1298,1299,1302,1304],{"class":150,"line":272},[148,1300,1301],{"class":667},"        yield",[148,1303,955],{"class":154},[148,1305,182],{"class":158},[148,1307,1308],{"class":150,"line":294},[148,1309,763],{"class":158},[148,1311,1312],{"class":150,"line":425},[148,1313,769],{"class":158},[148,1315,1316],{"class":150,"line":435},[148,1317,1107],{"emptyLinePlaceholder":1106},[148,1319,1320,1322,1324,1326,1328],{"class":150,"line":760},[148,1321,166],{"class":154},[148,1323,623],{"class":195},[148,1325,1117],{"class":158},[148,1327,196],{"class":195},[148,1329,350],{"class":158},[148,1331,1332,1334,1336,1338,1340,1343,1345,1347,1350],{"class":150,"line":766},[148,1333,1127],{"class":667},[148,1335,686],{"class":667},[148,1337,342],{"class":358},[148,1339,808],{"class":195},[148,1341,1342],{"class":678}," val",[148,1344,1139],{"class":682},[148,1346,1223],{"class":162},[148,1348,1349],{"class":358},"()) ",[148,1351,740],{"class":158},[148,1353,1354,1356,1358,1360,1362,1365,1367,1369],{"class":150,"line":1079},[148,1355,745],{"class":154},[148,1357,159],{"class":158},[148,1359,163],{"class":162},[148,1361,166],{"class":358},[148,1363,1364],{"class":154},"val",[148,1366,179],{"class":358},[148,1368,1164],{"class":158},[148,1370,1371],{"class":297}," \u002F\u002F 0,1,2 (每个间隔 100ms)\n",[148,1373,1374],{"class":150,"line":1085},[148,1375,763],{"class":158},[148,1377,1378,1380,1382],{"class":150,"line":1091},[148,1379,438],{"class":158},[148,1381,1180],{"class":154},[148,1383,182],{"class":158},[46,1385,1387],{"id":1386},"_3-典型应用","3. 典型应用",[57,1389,1390,1393,1396],{},[60,1391,1392],{},"处理分页 API 的流式数据。",[60,1394,1395],{},"读取大文件（Node.js 流）。",[60,1397,1398],{},"生成无限序列（如 WebSocket 消息流）。",[38,1400,1402],{"id":1401},"五abortcontroller-中止异步操作","五、AbortController 中止异步操作",[23,1404,1405,1408,1409,1412,1413,1416,1417,1420,1421,1424],{},[67,1406,1407],{},"AbortController"," 提供了一个标准方式来取消一个或多个异步操作（例如 ",[67,1410,1411],{},"fetch"," 请求、事件监听等）。",[27,1414,1415],{},"核心思想","：通过信号（",[67,1418,1419],{},"signal","）传递，调用 ",[67,1422,1423],{},"abort()"," 方法触发中断。",[46,1426,1428],{"id":1427},"_1-基本用法","1. 基本用法",[139,1430,1432],{"className":141,"code":1431,"language":143,"meta":144,"style":144},"const controller = new AbortController();\nconst { signal } = controller;\n\nfetch(\"\u002Fapi\u002Fdata\", { signal })\n    .then(res => res.json())\n    .catch(err => {\n        if (err.name === \"AbortError\") {\n            console.log(\"Fetch aborted\");\n        } else {\n            console.error(\"Other error:\", err);\n        }\n    });\n\n\u002F\u002F 取消请求\ncontroller.abort();\n",[67,1433,1434,1452,1470,1474,1499,1519,1533,1562,1583,1592,1618,1623,1631,1635,1640],{"__ignoreMap":144},[148,1435,1436,1438,1441,1443,1445,1448,1450],{"class":150,"line":151},[148,1437,808],{"class":195},[148,1439,1440],{"class":678}," controller",[148,1442,683],{"class":682},[148,1444,1268],{"class":682},[148,1446,1447],{"class":162}," AbortController",[148,1449,192],{"class":154},[148,1451,182],{"class":158},[148,1453,1454,1456,1459,1462,1464,1466,1468],{"class":150,"line":185},[148,1455,808],{"class":195},[148,1457,1458],{"class":158}," {",[148,1460,1461],{"class":678}," signal",[148,1463,1039],{"class":158},[148,1465,683],{"class":682},[148,1467,1440],{"class":154},[148,1469,182],{"class":158},[148,1471,1472],{"class":150,"line":228},[148,1473,1107],{"emptyLinePlaceholder":1106},[148,1475,1476,1478,1480,1482,1485,1487,1489,1491,1494,1496],{"class":150,"line":272},[148,1477,1411],{"class":162},[148,1479,166],{"class":154},[148,1481,170],{"class":169},[148,1483,1484],{"class":173},"\u002Fapi\u002Fdata",[148,1486,170],{"class":169},[148,1488,217],{"class":158},[148,1490,1458],{"class":158},[148,1492,1493],{"class":154}," signal ",[148,1495,438],{"class":158},[148,1497,1498],{"class":154},")\n",[148,1500,1501,1503,1505,1507,1509,1511,1513,1515,1517],{"class":150,"line":294},[148,1502,474],{"class":158},[148,1504,243],{"class":162},[148,1506,166],{"class":154},[148,1508,832],{"class":345},[148,1510,196],{"class":195},[148,1512,837],{"class":154},[148,1514,159],{"class":158},[148,1516,842],{"class":162},[148,1518,845],{"class":154},[148,1520,1521,1523,1525,1527,1529,1531],{"class":150,"line":425},[148,1522,474],{"class":158},[148,1524,534],{"class":162},[148,1526,166],{"class":154},[148,1528,539],{"class":345},[148,1530,196],{"class":195},[148,1532,350],{"class":158},[148,1534,1535,1538,1540,1542,1544,1547,1550,1553,1556,1558,1560],{"class":150,"line":435},[148,1536,1537],{"class":667},"        if",[148,1539,342],{"class":358},[148,1541,539],{"class":154},[148,1543,159],{"class":158},[148,1545,1546],{"class":154},"name",[148,1548,1549],{"class":682}," ===",[148,1551,1552],{"class":169}," \"",[148,1554,1555],{"class":173},"AbortError",[148,1557,170],{"class":169},[148,1559,737],{"class":358},[148,1561,740],{"class":158},[148,1563,1564,1566,1568,1570,1572,1574,1577,1579,1581],{"class":150,"line":760},[148,1565,401],{"class":154},[148,1567,159],{"class":158},[148,1569,163],{"class":162},[148,1571,166],{"class":358},[148,1573,170],{"class":169},[148,1575,1576],{"class":173},"Fetch aborted",[148,1578,170],{"class":169},[148,1580,179],{"class":358},[148,1582,182],{"class":158},[148,1584,1585,1587,1590],{"class":150,"line":766},[148,1586,418],{"class":158},[148,1588,1589],{"class":667}," else",[148,1591,350],{"class":158},[148,1593,1594,1596,1598,1600,1602,1604,1607,1609,1611,1614,1616],{"class":150,"line":1079},[148,1595,401],{"class":154},[148,1597,159],{"class":158},[148,1599,548],{"class":162},[148,1601,166],{"class":358},[148,1603,170],{"class":169},[148,1605,1606],{"class":173},"Other error:",[148,1608,170],{"class":169},[148,1610,217],{"class":158},[148,1612,1613],{"class":154}," err",[148,1615,179],{"class":358},[148,1617,182],{"class":158},[148,1619,1620],{"class":150,"line":1085},[148,1621,1622],{"class":158},"        }\n",[148,1624,1625,1627,1629],{"class":150,"line":1091},[148,1626,428],{"class":158},[148,1628,179],{"class":154},[148,1630,182],{"class":158},[148,1632,1633],{"class":150,"line":1097},[148,1634,1107],{"emptyLinePlaceholder":1106},[148,1636,1637],{"class":150,"line":1103},[148,1638,1639],{"class":297},"\u002F\u002F 取消请求\n",[148,1641,1642,1645,1647,1650,1652],{"class":150,"line":1110},[148,1643,1644],{"class":154},"controller",[148,1646,159],{"class":158},[148,1648,1649],{"class":162},"abort",[148,1651,192],{"class":154},[148,1653,182],{"class":158},[46,1655,1657],{"id":1656},"_2-中止多个请求","2. 中止多个请求",[23,1659,1660,1661,1663,1664,1666,1667,1669],{},"同一个 ",[67,1662,1419],{}," 可以传入多个 ",[67,1665,1411],{},"，调用一次 ",[67,1668,1423],{}," 会取消所有相关请求。",[46,1671,1673],{"id":1672},"_3-中止其他异步操作如事件监听","3. 中止其他异步操作（如事件监听）",[23,1675,1676,1677,1679,1680,1683,1684,65],{},"任何支持 ",[67,1678,1419],{}," 的 API 都可以使用，例如 ",[67,1681,1682],{},"addEventListener"," 的 ",[67,1685,1686],{},"AbortSignal",[139,1688,1690],{"className":141,"code":1689,"language":143,"meta":144,"style":144},"const controller = new AbortController();\nelement.addEventListener(\"click\", handler, { signal: controller.signal });\n\u002F\u002F 后续调用 controller.abort() 会移除该监听器\n",[67,1691,1692,1708,1752],{"__ignoreMap":144},[148,1693,1694,1696,1698,1700,1702,1704,1706],{"class":150,"line":151},[148,1695,808],{"class":195},[148,1697,1440],{"class":678},[148,1699,683],{"class":682},[148,1701,1268],{"class":682},[148,1703,1447],{"class":162},[148,1705,192],{"class":154},[148,1707,182],{"class":158},[148,1709,1710,1713,1715,1717,1719,1721,1724,1726,1728,1731,1733,1735,1737,1739,1741,1743,1746,1748,1750],{"class":150,"line":185},[148,1711,1712],{"class":154},"element",[148,1714,159],{"class":158},[148,1716,1682],{"class":162},[148,1718,166],{"class":154},[148,1720,170],{"class":169},[148,1722,1723],{"class":173},"click",[148,1725,170],{"class":169},[148,1727,217],{"class":158},[148,1729,1730],{"class":154}," handler",[148,1732,217],{"class":158},[148,1734,1458],{"class":158},[148,1736,1461],{"class":358},[148,1738,1020],{"class":158},[148,1740,1440],{"class":154},[148,1742,159],{"class":158},[148,1744,1745],{"class":154},"signal ",[148,1747,438],{"class":158},[148,1749,179],{"class":154},[148,1751,182],{"class":158},[148,1753,1754],{"class":150,"line":228},[148,1755,1756],{"class":297},"\u002F\u002F 后续调用 controller.abort() 会移除该监听器\n",[46,1758,1760],{"id":1759},"_4-手动实现可中止的异步任务","4. 手动实现可中止的异步任务",[23,1762,1763,1764,1683,1766,1768],{},"可以监听 ",[67,1765,1419],{},[67,1767,1649],{}," 事件，自定义清理逻辑。",[139,1770,1772],{"className":141,"code":1771,"language":143,"meta":144,"style":144},"function wait(ms, signal) {\n    return new Promise((resolve, reject) => {\n        const timer = setTimeout(resolve, ms);\n        signal?.addEventListener(\"abort\", () => {\n            clearTimeout(timer);\n            reject(new DOMException(\"Aborted\", \"AbortError\"));\n        });\n    });\n}\n\nconst controller = new AbortController();\nwait(5000, controller.signal).catch(err => console.log(err.name));\ncontroller.abort(); \u002F\u002F 立即中止\n",[67,1773,1774,1794,1820,1844,1870,1884,1918,1926,1934,1938,1942,1958,2003],{"__ignoreMap":144},[148,1775,1776,1778,1781,1783,1786,1788,1790,1792],{"class":150,"line":151},[148,1777,339],{"class":195},[148,1779,1780],{"class":162}," wait",[148,1782,166],{"class":158},[148,1784,1785],{"class":345},"ms",[148,1787,217],{"class":158},[148,1789,1461],{"class":345},[148,1791,179],{"class":158},[148,1793,350],{"class":158},[148,1795,1796,1799,1801,1803,1805,1807,1809,1811,1814,1816,1818],{"class":150,"line":185},[148,1797,1798],{"class":667},"    return",[148,1800,1268],{"class":682},[148,1802,1005],{"class":231},[148,1804,166],{"class":358},[148,1806,166],{"class":158},[148,1808,236],{"class":345},[148,1810,217],{"class":158},[148,1812,1813],{"class":345}," reject",[148,1815,179],{"class":158},[148,1817,196],{"class":195},[148,1819,350],{"class":158},[148,1821,1822,1824,1827,1829,1831,1833,1835,1837,1840,1842],{"class":150,"line":228},[148,1823,675],{"class":195},[148,1825,1826],{"class":678}," timer",[148,1828,683],{"class":682},[148,1830,1280],{"class":162},[148,1832,166],{"class":358},[148,1834,236],{"class":154},[148,1836,217],{"class":158},[148,1838,1839],{"class":154}," ms",[148,1841,179],{"class":358},[148,1843,182],{"class":158},[148,1845,1846,1849,1852,1854,1856,1858,1860,1862,1864,1866,1868],{"class":150,"line":272},[148,1847,1848],{"class":154},"        signal",[148,1850,1851],{"class":158},"?.",[148,1853,1682],{"class":162},[148,1855,166],{"class":358},[148,1857,170],{"class":169},[148,1859,1649],{"class":173},[148,1861,170],{"class":169},[148,1863,217],{"class":158},[148,1865,1117],{"class":158},[148,1867,196],{"class":195},[148,1869,350],{"class":158},[148,1871,1872,1875,1877,1880,1882],{"class":150,"line":294},[148,1873,1874],{"class":162},"            clearTimeout",[148,1876,166],{"class":358},[148,1878,1879],{"class":154},"timer",[148,1881,179],{"class":358},[148,1883,182],{"class":158},[148,1885,1886,1889,1891,1894,1897,1899,1901,1904,1906,1908,1910,1912,1914,1916],{"class":150,"line":425},[148,1887,1888],{"class":162},"            reject",[148,1890,166],{"class":358},[148,1892,1893],{"class":682},"new",[148,1895,1896],{"class":162}," DOMException",[148,1898,166],{"class":358},[148,1900,170],{"class":169},[148,1902,1903],{"class":173},"Aborted",[148,1905,170],{"class":169},[148,1907,217],{"class":158},[148,1909,1552],{"class":169},[148,1911,1555],{"class":173},[148,1913,170],{"class":169},[148,1915,267],{"class":358},[148,1917,182],{"class":158},[148,1919,1920,1922,1924],{"class":150,"line":435},[148,1921,418],{"class":158},[148,1923,179],{"class":358},[148,1925,182],{"class":158},[148,1927,1928,1930,1932],{"class":150,"line":760},[148,1929,428],{"class":158},[148,1931,179],{"class":358},[148,1933,182],{"class":158},[148,1935,1936],{"class":150,"line":766},[148,1937,769],{"class":158},[148,1939,1940],{"class":150,"line":1079},[148,1941,1107],{"emptyLinePlaceholder":1106},[148,1943,1944,1946,1948,1950,1952,1954,1956],{"class":150,"line":1085},[148,1945,808],{"class":195},[148,1947,1440],{"class":678},[148,1949,683],{"class":682},[148,1951,1268],{"class":682},[148,1953,1447],{"class":162},[148,1955,192],{"class":154},[148,1957,182],{"class":158},[148,1959,1960,1963,1965,1968,1970,1972,1974,1977,1979,1981,1983,1985,1987,1989,1991,1993,1996,1998,2001],{"class":150,"line":1091},[148,1961,1962],{"class":162},"wait",[148,1964,166],{"class":154},[148,1966,1967],{"class":220},"5000",[148,1969,217],{"class":158},[148,1971,1440],{"class":154},[148,1973,159],{"class":158},[148,1975,1976],{"class":154},"signal)",[148,1978,159],{"class":158},[148,1980,534],{"class":162},[148,1982,166],{"class":154},[148,1984,539],{"class":345},[148,1986,196],{"class":195},[148,1988,199],{"class":154},[148,1990,159],{"class":158},[148,1992,163],{"class":162},[148,1994,1995],{"class":154},"(err",[148,1997,159],{"class":158},[148,1999,2000],{"class":154},"name))",[148,2002,182],{"class":158},[148,2004,2005,2007,2009,2011,2013,2015],{"class":150,"line":1097},[148,2006,1644],{"class":154},[148,2008,159],{"class":158},[148,2010,1649],{"class":162},[148,2012,192],{"class":154},[148,2014,1164],{"class":158},[148,2016,2017],{"class":297}," \u002F\u002F 立即中止\n",[46,2019,2021],{"id":2020},"_5-注意要点","5. 注意要点",[57,2023,2024,2032],{},[60,2025,2026,2028,2029,2031],{},[67,2027,1407],{}," 只能触发一次 ",[67,2030,1649],{},"，不可复用。",[60,2033,2034,2035,453,2037,2039,2040,2042,2043,74,2046,2049],{},"浏览器原生支持 ",[67,2036,1411],{},[67,2038,1682],{},"，Node.js 从 v15+ 开始支持 ",[67,2041,1407],{}," 用于 ",[67,2044,2045],{},"fs",[67,2047,2048],{},"http"," 等模块。",[38,2051,2052],{"id":2052},"总结",[2054,2055,2056,2069],"table",{},[2057,2058,2059],"thead",{},[2060,2061,2062,2066],"tr",{},[2063,2064,2065],"th",{},"概念",[2063,2067,2068],{},"核心要点",[2070,2071,2072,2080,2087,2094,2107],"tbody",{},[2060,2073,2074,2077],{},[2075,2076,29],"td",{},[2075,2078,2079],{},"宏任务与微任务的优先级模型，决定了异步代码的执行时机",[2060,2081,2082,2084],{},[2075,2083,86],{},[2075,2085,2086],{},"链式调用、静态方法（all\u002FallSettled\u002Fany\u002Frace）、错误冒泡",[2060,2088,2089,2091],{},[2075,2090,613],{},[2075,2092,2093],{},"基于生成器 + 自动执行器的语法糖，配合 try\u002Fcatch 或 .catch 处理错误",[2060,2095,2096,2099],{},[2075,2097,2098],{},"异步迭代器\u002F生成器",[2075,2100,2101,2103,2104,2106],{},[67,2102,916],{}," 消费异步数据流，",[67,2105,1192],{}," 生产异步序列",[2060,2108,2109,2111],{},[2075,2110,1407],{},[2075,2112,2113,2114,2116],{},"通过 ",[67,2115,1419],{}," 取消 fetch、事件监听等，可自定义中止逻辑",[23,2118,2119],{},"掌握这些内容，就能高效处理 JavaScript 中几乎所有的异步场景，写出清晰、健壮且可取消的异步代码。",[38,2121,2122],{"id":2122},"参考文献",[23,2124,2125],{},"以下链接在编写时均可正常访问：",[2054,2127,2128,2138],{},[2057,2129,2130],{},[2060,2131,2132,2135],{},[2063,2133,2134],{},"资料",[2063,2136,2137],{},"说明",[2070,2139,2140,2152,2164,2175,2187],{},[2060,2141,2142,2150],{},[2075,2143,2144],{},[32,2145,2149],{"href":2146,"rel":2147},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-CN\u002Fdocs\u002FWeb\u002FJavaScript\u002FEvent_loop",[2148],"nofollow","MDN：并发模型与事件循环",[2075,2151,29],{},[2060,2153,2154,2161],{},[2075,2155,2156],{},[32,2157,2160],{"href":2158,"rel":2159},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-CN\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise",[2148],"MDN：Promise",[2075,2162,2163],{},"Promise API",[2060,2165,2166,2173],{},[2075,2167,2168],{},[32,2169,2172],{"href":2170,"rel":2171},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-CN\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fasync_function",[2148],"MDN：async function",[2075,2174,613],{},[2060,2176,2177,2184],{},[2075,2178,2179],{},[32,2180,2183],{"href":2181,"rel":2182},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-CN\u002Fdocs\u002FWeb\u002FAPI\u002FAbortController",[2148],"MDN：AbortController",[2075,2185,2186],{},"中止异步操作",[2060,2188,2189,2196],{},[2075,2190,2191],{},[32,2192,2195],{"href":2193,"rel":2194},"https:\u002F\u002Fhtml.spec.whatwg.org\u002Fmultipage\u002Fwebappapis.html#event-loops",[2148],"HTML：event loop",[2075,2197,2198],{},"浏览器事件循环（英文）",[2200,2201,2202],"style",{},"html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVXei, html code.shiki .sVXei{--shiki-light:#E53935;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":144,"searchDepth":185,"depth":185,"links":2204},[2205,2210,2216,2222,2227,2234,2235],{"id":40,"depth":185,"text":41,"children":2206},[2207,2208,2209],{"id":48,"depth":228,"text":49},{"id":121,"depth":228,"text":122},{"id":301,"depth":228,"text":302},{"id":316,"depth":185,"text":317,"children":2211},[2212,2213,2214,2215],{"id":320,"depth":228,"text":321},{"id":445,"depth":228,"text":446},{"id":556,"depth":228,"text":557},{"id":590,"depth":228,"text":591},{"id":607,"depth":185,"text":608,"children":2217},[2218,2219,2220,2221],{"id":617,"depth":228,"text":618},{"id":643,"depth":228,"text":644},{"id":772,"depth":228,"text":773},{"id":881,"depth":228,"text":882},{"id":894,"depth":185,"text":895,"children":2223},[2224,2225,2226],{"id":898,"depth":228,"text":899},{"id":1185,"depth":228,"text":1186},{"id":1386,"depth":228,"text":1387},{"id":1401,"depth":185,"text":1402,"children":2228},[2229,2230,2231,2232,2233],{"id":1427,"depth":228,"text":1428},{"id":1656,"depth":228,"text":1657},{"id":1672,"depth":228,"text":1673},{"id":1759,"depth":228,"text":1760},{"id":2020,"depth":228,"text":2021},{"id":2052,"depth":185,"text":2052},{"id":2122,"depth":185,"text":2122},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fweb\u002FJs\u002Fevent-loop","knowledge\u002Fknowledge\u002Fbooklet\u002Fweb\u002FJs\u002Fevent-loop.md","md",{"items":2241},[2242,2246,2250,2254,2258,2262],{"path":2243,"title":2244,"description":2245,"category":10,"score":425},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Ferror","错误处理与调试","结构化错误类型、try\u002Fcatch 与全局未捕获处理是健壮应用的基础。",{"path":2247,"title":2248,"description":2249,"category":10,"score":425},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fdom-bom","浏览器相关 API","DOM 事件、存储、fetch、Worker、Observer 等由浏览器提供的 Web API（非 ECMAScript 核心）。HTML 结构见 标签。",{"path":2251,"title":2252,"description":2253,"category":10,"score":425},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fperformance","性能优化","防抖\u002F节流、渲染与内存、资源预加载及引擎行为是前端性能的主要抓手。相关 CSS 见 视觉效果、Head 资源提示。",{"path":2255,"title":2256,"description":2257,"category":10,"score":425},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fcommon","模块化与工程化","ESM、CommonJS 与打包工具（Tree Shaking、代码分割）是前端工程化的基础。入门见 JavaScript 基础 · 模块。",{"path":2259,"title":2260,"description":2261,"category":10,"score":425},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fscope","执行模型与作用域","执行上下文与词法作用域决定变量在何处可访问、闭包如何形成，以及 var \u002F let \u002F const 的差异。语言概览见 JavaScript 基础。",{"path":2263,"title":2264,"description":2265,"category":10,"score":425},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fmap-set","数据结构与集合增强","Map \u002F Set、WeakMap \u002F WeakSet、数组高阶方法、TypedArray 与 Symbol 等扩展了内置数据结构能力。见 语言基础。",{"series":2267,"title":143,"items":2268,"index":425,"prev":2309,"next":2310},"booklet\u002Fweb\u002Fjs",[2269,2273,2276,2278,2282,2284,2286,2287,2291,2293,2295,2299,2303,2307],{"path":2270,"title":2271,"date":2272,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fadvanced","函数进阶","2022-10-24",{"path":34,"title":2274,"date":2275,"pinned":15},"JavaScript 基础","2023-11-24",{"path":2255,"title":2256,"date":2277,"pinned":15},"2025-06-21",{"path":2279,"title":2280,"date":2281,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fdesign","设计模式","2021-10-05",{"path":2247,"title":2248,"date":2283,"pinned":15},"2025-07-10",{"path":2243,"title":2244,"date":2285,"pinned":15},"2026-06-25",{"path":7,"title":8,"date":14,"pinned":15},{"path":2288,"title":2289,"date":2290,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fexec","正则表达式","2022-05-21",{"path":2263,"title":2264,"date":2292,"pinned":15},"2024-07-10",{"path":2251,"title":2252,"date":2294,"pinned":15},"2025-07-04",{"path":2296,"title":2297,"date":2298,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fprototype","原型与面向对象","2020-04-13",{"path":2300,"title":2301,"date":2302,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fproxy","代理与反射","2022-10-23",{"path":2304,"title":2305,"date":2306,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fweb\u002Fjs\u002Fsafe","安全","2023-06-26",{"path":2259,"title":2260,"date":2308,"pinned":15},"2025-01-29",{"path":2243,"title":2244,"date":2285,"pinned":15},{"path":2288,"title":2289,"date":2290,"pinned":15}]