[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fbase\u002Fmodule":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fbase\u002Fmodule":2100,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fbase\u002Fmodule":2126},{"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":2096,"stem":2097,"id":2098,"extension":2099},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fbase\u002Fmodule","模块系统","Node.js 的模块系统是其核心设计之一，它允许开发者将代码拆分为多个文件（模块），通过 require（CommonJS）或 import\u002Fexport（ESM）进行组织和复用。下面详细介绍 CommonJS、ESM 以及两者的互操作。","技能小册",[12,13],"nodejs","module","2020-07-01",false,{"type":17,"value":18,"toc":2087},"minimark",[19,22,27,40,45,55,63,70,139,144,209,214,346,350,378,382,389,393,757,762,770,775,811,815,826,830,836,870,874,937,1047,1054,1060,1212,1216,1374,1378,1381,1385,1423,1427,1572,1581,1585,1601,1717,1740,1825,1840,1844,1884,1887,2033,2036,2080,2083],[20,21,8],"h1",{"id":8},[23,24,26],"h2",{"id":25},"nodejs-模块系统","Node.js 模块系统",[28,29,30,31,35,36,39],"p",{},"Node.js 的模块系统是其核心设计之一，它允许开发者将代码拆分为多个文件（模块），通过 ",[32,33,34],"code",{},"require","（CommonJS）或 ",[32,37,38],{},"import\u002Fexport","（ESM）进行组织和复用。下面详细介绍 CommonJS、ESM 以及两者的互操作。",[41,42,44],"h3",{"id":43},"一commonjs-规范","一、CommonJS 规范",[28,46,47,48,51,52,54],{},"CommonJS 是 Node.js 原生支持的模块系统，每个文件都是一个独立的模块，拥有自己的作用域。模块通过 ",[32,49,50],{},"module.exports"," 导出内容，通过 ",[32,53,34],{}," 导入其他模块。",[56,57,59,60,62],"h4",{"id":58},"_1-require-的加载机制","1. ",[32,61,34],{}," 的加载机制",[28,64,65,69],{},[66,67,68],"strong",{},"基本规则","：",[71,72,73],"ul",{},[74,75,76,78,79],"li",{},[32,77,34],{}," 可以传入模块标识符：\n",[71,80,81,95,117,126],{},[74,82,83,86,87,90,91,94],{},[66,84,85],{},"核心模块","：如 ",[32,88,89],{},"fs","、",[32,92,93],{},"path","，直接返回内置模块。",[74,96,97,86,100,90,103,106,107,90,110,90,113,116],{},[66,98,99],{},"相对路径",[32,101,102],{},"'.\u002Fmod'",[32,104,105],{},"'..\u002Flib'","，会解析为当前文件所在目录下的文件（可省略 ",[32,108,109],{},".js",[32,111,112],{},".json",[32,114,115],{},".node"," 扩展名）。",[74,118,119,86,122,125],{},[66,120,121],{},"绝对路径",[32,123,124],{},"'\u002Fusr\u002Flocal\u002Flib\u002Fmod'","。",[74,127,128,86,131,134,135,138],{},[66,129,130],{},"包名",[32,132,133],{},"'lodash'","，Node.js 会从当前目录开始向上查找 ",[32,136,137],{},"node_modules"," 目录，找到对应的包后加载其入口文件。",[28,140,141,69],{},[66,142,143],{},"加载步骤",[145,146,147,156,166,181,200],"ol",{},[74,148,149,152,153,155],{},[66,150,151],{},"解析路径","：将模块标识符转换为绝对路径（如果是包名，则查找 ",[32,154,137],{},"）。",[74,157,158,161,162,165],{},[66,159,160],{},"检查缓存","：如果模块已被加载，直接从缓存中返回 ",[32,163,164],{},"exports"," 对象，不重复执行模块代码。",[74,167,168,171,172,90,175,90,177,180],{},[66,169,170],{},"创建模块对象","：包括 ",[32,173,174],{},"id",[32,176,164],{},[32,178,179],{},"parent"," 等属性。",[74,182,183,186,187,90,189,90,191,90,193,90,196,199],{},[66,184,185],{},"编译执行","：读取模块代码，将其包裹在一个函数中执行（注入 ",[32,188,164],{},[32,190,34],{},[32,192,13],{},[32,194,195],{},"__filename",[32,197,198],{},"__dirname"," 等变量）。",[74,201,202,205,206,208],{},[66,203,204],{},"返回导出内容","：模块执行后的 ",[32,207,50],{}," 被缓存并返回。",[28,210,211,69],{},[66,212,213],{},"示例",[215,216,221],"pre",{"className":217,"code":218,"language":219,"meta":220,"style":220},"language-js shiki shiki-themes material-theme-lighter github-light github-dark","\u002F\u002F a.js\nmodule.exports = { foo: \"bar\" };\n\n\u002F\u002F b.js\nconst a = require(\".\u002Fa\"); \u002F\u002F 加载 a.js\nconsole.log(a.foo); \u002F\u002F 'bar'\n","js","",[32,222,223,232,272,279,285,322],{"__ignoreMap":220},[224,225,228],"span",{"class":226,"line":227},"line",1,[224,229,231],{"class":230},"sutJx","\u002F\u002F a.js\n",[224,233,235,238,242,244,248,251,255,258,262,266,269],{"class":226,"line":234},2,[224,236,13],{"class":237},"s39Yj",[224,239,241],{"class":240},"sP7_E",".",[224,243,164],{"class":237},[224,245,247],{"class":246},"smGrS"," =",[224,249,250],{"class":240}," {",[224,252,254],{"class":253},"skxfh"," foo",[224,256,257],{"class":240},":",[224,259,261],{"class":260},"sjJ54"," \"",[224,263,265],{"class":264},"s_sjI","bar",[224,267,268],{"class":260},"\"",[224,270,271],{"class":240}," };\n",[224,273,275],{"class":226,"line":274},3,[224,276,278],{"emptyLinePlaceholder":277},true,"\n",[224,280,282],{"class":226,"line":281},4,[224,283,284],{"class":230},"\u002F\u002F b.js\n",[224,286,288,292,296,298,302,306,308,311,313,316,319],{"class":226,"line":287},5,[224,289,291],{"class":290},"sbsja","const",[224,293,295],{"class":294},"s_hVV"," a",[224,297,247],{"class":246},[224,299,301],{"class":300},"sGLFI"," require",[224,303,305],{"class":304},"su5hD","(",[224,307,268],{"class":260},[224,309,310],{"class":264},".\u002Fa",[224,312,268],{"class":260},[224,314,315],{"class":304},")",[224,317,318],{"class":240},";",[224,320,321],{"class":230}," \u002F\u002F 加载 a.js\n",[224,323,325,328,330,333,336,338,341,343],{"class":226,"line":324},6,[224,326,327],{"class":304},"console",[224,329,241],{"class":240},[224,331,332],{"class":300},"log",[224,334,335],{"class":304},"(a",[224,337,241],{"class":240},[224,339,340],{"class":304},"foo)",[224,342,318],{"class":240},[224,344,345],{"class":230}," \u002F\u002F 'bar'\n",[56,347,349],{"id":348},"_2-缓存机制","2. 缓存机制",[71,351,352,362,371],{},[74,353,354,355,357,358,361],{},"每个模块第一次 ",[32,356,34],{}," 后会被缓存到 ",[32,359,360],{},"require.cache"," 对象中（键为模块的绝对路径）。",[74,363,364,365,367,368,370],{},"多次 ",[32,366,34],{}," 同一个模块会返回同一个 ",[32,369,164],{}," 对象，模块内的代码只执行一次。",[74,372,373,374,377],{},"可以通过 ",[32,375,376],{},"delete require.cache[modulePath]"," 清除缓存（不推荐在生产环境使用，除非特殊热更新场景）。",[56,379,381],{"id":380},"_3-循环依赖处理","3. 循环依赖处理",[28,383,384,385,388],{},"当两个模块互相引用时，CommonJS 采用了",[66,386,387],{},"有限加载","策略：在循环依赖发生时，模块会返回当前已执行部分导出的内容，尚未执行的部分暂为空。这样可以避免无限递归。",[28,390,391,69],{},[66,392,213],{},[215,394,396],{"className":217,"code":395,"language":219,"meta":220,"style":220},"\u002F\u002F a.js\nconsole.log(\"a starting\");\nexports.done = false;\nconst b = require(\".\u002Fb\");\nconsole.log(\"in a, b.done =\", b.done);\nexports.done = true;\nconsole.log(\"a done\");\n\n\u002F\u002F b.js\nconsole.log(\"b starting\");\nexports.done = false;\nconst a = require(\".\u002Fa\");\nconsole.log(\"in b, a.done =\", a.done);\nexports.done = true;\nconsole.log(\"b done\");\n\n\u002F\u002F main.js\nconst a = require(\".\u002Fa\");\nconsole.log(\"in main, a.done =\", a.done, \"b.done =\", require(\".\u002Fb\").done);\n",[32,397,398,402,424,442,466,495,510,532,537,542,564,579,602,630,645,667,672,678,701],{"__ignoreMap":220},[224,399,400],{"class":226,"line":227},[224,401,231],{"class":230},[224,403,404,406,408,410,412,414,417,419,421],{"class":226,"line":234},[224,405,327],{"class":304},[224,407,241],{"class":240},[224,409,332],{"class":300},[224,411,305],{"class":304},[224,413,268],{"class":260},[224,415,416],{"class":264},"a starting",[224,418,268],{"class":260},[224,420,315],{"class":304},[224,422,423],{"class":240},";\n",[224,425,426,428,430,433,436,440],{"class":226,"line":274},[224,427,164],{"class":237},[224,429,241],{"class":240},[224,431,432],{"class":304},"done ",[224,434,435],{"class":246},"=",[224,437,439],{"class":438},"syTEX"," false",[224,441,423],{"class":240},[224,443,444,446,449,451,453,455,457,460,462,464],{"class":226,"line":281},[224,445,291],{"class":290},[224,447,448],{"class":294}," b",[224,450,247],{"class":246},[224,452,301],{"class":300},[224,454,305],{"class":304},[224,456,268],{"class":260},[224,458,459],{"class":264},".\u002Fb",[224,461,268],{"class":260},[224,463,315],{"class":304},[224,465,423],{"class":240},[224,467,468,470,472,474,476,478,481,483,486,488,490,493],{"class":226,"line":287},[224,469,327],{"class":304},[224,471,241],{"class":240},[224,473,332],{"class":300},[224,475,305],{"class":304},[224,477,268],{"class":260},[224,479,480],{"class":264},"in a, b.done =",[224,482,268],{"class":260},[224,484,485],{"class":240},",",[224,487,448],{"class":304},[224,489,241],{"class":240},[224,491,492],{"class":304},"done)",[224,494,423],{"class":240},[224,496,497,499,501,503,505,508],{"class":226,"line":324},[224,498,164],{"class":237},[224,500,241],{"class":240},[224,502,432],{"class":304},[224,504,435],{"class":246},[224,506,507],{"class":438}," true",[224,509,423],{"class":240},[224,511,513,515,517,519,521,523,526,528,530],{"class":226,"line":512},7,[224,514,327],{"class":304},[224,516,241],{"class":240},[224,518,332],{"class":300},[224,520,305],{"class":304},[224,522,268],{"class":260},[224,524,525],{"class":264},"a done",[224,527,268],{"class":260},[224,529,315],{"class":304},[224,531,423],{"class":240},[224,533,535],{"class":226,"line":534},8,[224,536,278],{"emptyLinePlaceholder":277},[224,538,540],{"class":226,"line":539},9,[224,541,284],{"class":230},[224,543,545,547,549,551,553,555,558,560,562],{"class":226,"line":544},10,[224,546,327],{"class":304},[224,548,241],{"class":240},[224,550,332],{"class":300},[224,552,305],{"class":304},[224,554,268],{"class":260},[224,556,557],{"class":264},"b starting",[224,559,268],{"class":260},[224,561,315],{"class":304},[224,563,423],{"class":240},[224,565,567,569,571,573,575,577],{"class":226,"line":566},11,[224,568,164],{"class":237},[224,570,241],{"class":240},[224,572,432],{"class":304},[224,574,435],{"class":246},[224,576,439],{"class":438},[224,578,423],{"class":240},[224,580,582,584,586,588,590,592,594,596,598,600],{"class":226,"line":581},12,[224,583,291],{"class":290},[224,585,295],{"class":294},[224,587,247],{"class":246},[224,589,301],{"class":300},[224,591,305],{"class":304},[224,593,268],{"class":260},[224,595,310],{"class":264},[224,597,268],{"class":260},[224,599,315],{"class":304},[224,601,423],{"class":240},[224,603,605,607,609,611,613,615,618,620,622,624,626,628],{"class":226,"line":604},13,[224,606,327],{"class":304},[224,608,241],{"class":240},[224,610,332],{"class":300},[224,612,305],{"class":304},[224,614,268],{"class":260},[224,616,617],{"class":264},"in b, a.done =",[224,619,268],{"class":260},[224,621,485],{"class":240},[224,623,295],{"class":304},[224,625,241],{"class":240},[224,627,492],{"class":304},[224,629,423],{"class":240},[224,631,633,635,637,639,641,643],{"class":226,"line":632},14,[224,634,164],{"class":237},[224,636,241],{"class":240},[224,638,432],{"class":304},[224,640,435],{"class":246},[224,642,507],{"class":438},[224,644,423],{"class":240},[224,646,648,650,652,654,656,658,661,663,665],{"class":226,"line":647},15,[224,649,327],{"class":304},[224,651,241],{"class":240},[224,653,332],{"class":300},[224,655,305],{"class":304},[224,657,268],{"class":260},[224,659,660],{"class":264},"b done",[224,662,268],{"class":260},[224,664,315],{"class":304},[224,666,423],{"class":240},[224,668,670],{"class":226,"line":669},16,[224,671,278],{"emptyLinePlaceholder":277},[224,673,675],{"class":226,"line":674},17,[224,676,677],{"class":230},"\u002F\u002F main.js\n",[224,679,681,683,685,687,689,691,693,695,697,699],{"class":226,"line":680},18,[224,682,291],{"class":290},[224,684,295],{"class":294},[224,686,247],{"class":246},[224,688,301],{"class":300},[224,690,305],{"class":304},[224,692,268],{"class":260},[224,694,310],{"class":264},[224,696,268],{"class":260},[224,698,315],{"class":304},[224,700,423],{"class":240},[224,702,704,706,708,710,712,714,717,719,721,723,725,728,730,732,735,737,739,741,743,745,747,749,751,753,755],{"class":226,"line":703},19,[224,705,327],{"class":304},[224,707,241],{"class":240},[224,709,332],{"class":300},[224,711,305],{"class":304},[224,713,268],{"class":260},[224,715,716],{"class":264},"in main, a.done =",[224,718,268],{"class":260},[224,720,485],{"class":240},[224,722,295],{"class":304},[224,724,241],{"class":240},[224,726,727],{"class":304},"done",[224,729,485],{"class":240},[224,731,261],{"class":260},[224,733,734],{"class":264},"b.done =",[224,736,268],{"class":260},[224,738,485],{"class":240},[224,740,301],{"class":300},[224,742,305],{"class":304},[224,744,268],{"class":260},[224,746,459],{"class":264},[224,748,268],{"class":260},[224,750,315],{"class":304},[224,752,241],{"class":240},[224,754,492],{"class":304},[224,756,423],{"class":240},[28,758,759,69],{},[66,760,761],{},"输出顺序",[215,763,768],{"className":764,"code":766,"language":767},[765],"language-text","a starting\nb starting\nin b, a.done = false   \u002F\u002F a 尚未执行完，其 exports 只包含初始的 done: false\nb done\nin a, b.done = true\na done\nin main, a.done = true b.done = true\n","text",[32,769,766],{"__ignoreMap":220},[28,771,772,69],{},[66,773,774],{},"关键点",[71,776,777,808],{},[74,778,779,780,783,784,787,788,791,792,794,795,797,798,801,802,804,805,155],{},"在 ",[32,781,782],{},"a.js"," 中 ",[32,785,786],{},"require('.\u002Fb')"," 时，",[32,789,790],{},"b.js"," 中又引用了 ",[32,793,782],{},"，但此时 ",[32,796,782],{}," 还没有执行完，",[32,799,800],{},"a"," 的 ",[32,803,164],{}," 只包含已经执行部分的导出（",[32,806,807],{},"done: false",[74,809,810],{},"这种机制使得循环依赖不会导致死锁，但需要开发者确保依赖关系不会造成未定义行为。",[41,812,814],{"id":813},"二es-模块esm支持","二、ES 模块（ESM）支持",[28,816,817,818,821,822,825],{},"Node.js 从 12 版本开始稳定支持 ES 模块（以下简称 ESM），并在后续版本中持续完善。ESM 使用 ",[32,819,820],{},"import"," 和 ",[32,823,824],{},"export"," 语法，与浏览器保持一致。",[56,827,829],{"id":828},"_1-启用-esm-的方式","1. 启用 ESM 的方式",[28,831,832,833,835],{},"有两种方式告诉 Node.js 将 ",[32,834,109],{}," 文件视为 ES 模块：",[71,837,838,851],{},[74,839,840,847,848,850],{},[66,841,842,843,846],{},"使用 ",[32,844,845],{},".mjs"," 扩展名","：文件以 ",[32,849,845],{}," 结尾，Node.js 默认以 ESM 处理。",[74,852,853,862,863,865,866,869],{},[66,854,779,855,858,859],{},[32,856,857],{},"package.json"," 中设置 ",[32,860,861],{},"\"type\": \"module\"","：此时项目下所有 ",[32,864,109],{}," 文件被视为 ESM；若想个别文件使用 CommonJS，可使用 ",[32,867,868],{},".cjs"," 扩展名。",[28,871,872,69],{},[66,873,213],{},[215,875,879],{"className":876,"code":877,"language":878,"meta":220,"style":220},"language-json shiki shiki-themes material-theme-lighter github-light github-dark","\u002F\u002F package.json\n{\n  \"type\": \"module\",\n  \"dependencies\": {...}\n}\n","json",[32,880,881,886,891,913,933],{"__ignoreMap":220},[224,882,883],{"class":226,"line":227},[224,884,885],{"class":230},"\u002F\u002F package.json\n",[224,887,888],{"class":226,"line":234},[224,889,890],{"class":240},"{\n",[224,892,893,896,900,902,904,906,908,910],{"class":226,"line":274},[224,894,895],{"class":237},"  \"",[224,897,899],{"class":898},"sseR_","type",[224,901,268],{"class":237},[224,903,257],{"class":240},[224,905,261],{"class":260},[224,907,13],{"class":264},[224,909,268],{"class":260},[224,911,912],{"class":240},",\n",[224,914,915,917,920,922,924,926,930],{"class":226,"line":281},[224,916,895],{"class":237},[224,918,919],{"class":898},"dependencies",[224,921,268],{"class":237},[224,923,257],{"class":240},[224,925,250],{"class":240},[224,927,929],{"class":928},"srjyR","...",[224,931,932],{"class":240},"}\n",[224,934,935],{"class":226,"line":287},[224,936,932],{"class":240},[215,938,940],{"className":217,"code":939,"language":219,"meta":220,"style":220},"\u002F\u002F math.mjs 或 math.js (当 type: module)\nexport const add = (a, b) => a + b;\n\n\u002F\u002F app.mjs 或 app.js\nimport { add } from \".\u002Fmath.js\";\nconsole.log(add(1, 2));\n",[32,941,942,947,986,990,995,1018],{"__ignoreMap":220},[224,943,944],{"class":226,"line":227},[224,945,946],{"class":230},"\u002F\u002F math.mjs 或 math.js (当 type: module)\n",[224,948,949,952,955,959,961,964,967,969,971,973,976,979,982,984],{"class":226,"line":234},[224,950,824],{"class":951},"sVHd0",[224,953,954],{"class":290}," const",[224,956,958],{"class":957},"sfCm-"," add",[224,960,247],{"class":246},[224,962,963],{"class":240}," (",[224,965,800],{"class":966},"s99_P",[224,968,485],{"class":240},[224,970,448],{"class":966},[224,972,315],{"class":240},[224,974,975],{"class":290}," =>",[224,977,978],{"class":304}," a ",[224,980,981],{"class":246},"+",[224,983,448],{"class":304},[224,985,423],{"class":240},[224,987,988],{"class":226,"line":274},[224,989,278],{"emptyLinePlaceholder":277},[224,991,992],{"class":226,"line":281},[224,993,994],{"class":230},"\u002F\u002F app.mjs 或 app.js\n",[224,996,997,999,1001,1003,1006,1009,1011,1014,1016],{"class":226,"line":287},[224,998,820],{"class":951},[224,1000,250],{"class":240},[224,1002,958],{"class":304},[224,1004,1005],{"class":240}," }",[224,1007,1008],{"class":951}," from",[224,1010,261],{"class":260},[224,1012,1013],{"class":264},".\u002Fmath.js",[224,1015,268],{"class":260},[224,1017,423],{"class":240},[224,1019,1020,1022,1024,1026,1028,1031,1033,1037,1039,1042,1045],{"class":226,"line":324},[224,1021,327],{"class":304},[224,1023,241],{"class":240},[224,1025,332],{"class":300},[224,1027,305],{"class":304},[224,1029,1030],{"class":300},"add",[224,1032,305],{"class":304},[224,1034,1036],{"class":1035},"srdBf","1",[224,1038,485],{"class":240},[224,1040,1041],{"class":1035}," 2",[224,1043,1044],{"class":304},"))",[224,1046,423],{"class":240},[56,1048,1050,1051],{"id":1049},"_2-动态导入-import","2. 动态导入 ",[32,1052,1053],{},"import()",[28,1055,1056,1057,1059],{},"ESM 提供了 ",[32,1058,1053],{}," 函数，支持异步动态加载模块。它返回一个 Promise，可以在任何地方（包括 CommonJS 模块）使用。这对于代码分割、按需加载非常有用。",[215,1061,1063],{"className":217,"code":1062,"language":219,"meta":220,"style":220},"\u002F\u002F 动态导入\nconst module = await import(\".\u002Fsome-module.js\");\nconsole.log(module.default);\n\n\u002F\u002F 在 CommonJS 中使用\nsetTimeout(async () => {\n  const { add } = await import(\".\u002Fmath.js\");\n  console.log(add(3, 4));\n}, 1000);\n",[32,1064,1065,1070,1098,1117,1121,1126,1144,1173,1200],{"__ignoreMap":220},[224,1066,1067],{"class":226,"line":227},[224,1068,1069],{"class":230},"\u002F\u002F 动态导入\n",[224,1071,1072,1074,1077,1079,1082,1085,1087,1089,1092,1094,1096],{"class":226,"line":234},[224,1073,291],{"class":290},[224,1075,1076],{"class":294}," module",[224,1078,247],{"class":246},[224,1080,1081],{"class":951}," await",[224,1083,1084],{"class":246}," import",[224,1086,305],{"class":304},[224,1088,268],{"class":260},[224,1090,1091],{"class":264},".\u002Fsome-module.js",[224,1093,268],{"class":260},[224,1095,315],{"class":304},[224,1097,423],{"class":240},[224,1099,1100,1102,1104,1106,1108,1110,1112,1115],{"class":226,"line":274},[224,1101,327],{"class":304},[224,1103,241],{"class":240},[224,1105,332],{"class":300},[224,1107,305],{"class":304},[224,1109,13],{"class":237},[224,1111,241],{"class":240},[224,1113,1114],{"class":304},"default)",[224,1116,423],{"class":240},[224,1118,1119],{"class":226,"line":281},[224,1120,278],{"emptyLinePlaceholder":277},[224,1122,1123],{"class":226,"line":287},[224,1124,1125],{"class":230},"\u002F\u002F 在 CommonJS 中使用\n",[224,1127,1128,1131,1133,1136,1139,1141],{"class":226,"line":324},[224,1129,1130],{"class":300},"setTimeout",[224,1132,305],{"class":304},[224,1134,1135],{"class":290},"async",[224,1137,1138],{"class":240}," ()",[224,1140,975],{"class":290},[224,1142,1143],{"class":240}," {\n",[224,1145,1146,1149,1151,1153,1155,1157,1159,1161,1163,1165,1167,1169,1171],{"class":226,"line":512},[224,1147,1148],{"class":290},"  const",[224,1150,250],{"class":240},[224,1152,958],{"class":294},[224,1154,1005],{"class":240},[224,1156,247],{"class":246},[224,1158,1081],{"class":951},[224,1160,1084],{"class":246},[224,1162,305],{"class":253},[224,1164,268],{"class":260},[224,1166,1013],{"class":264},[224,1168,268],{"class":260},[224,1170,315],{"class":253},[224,1172,423],{"class":240},[224,1174,1175,1178,1180,1182,1184,1186,1188,1191,1193,1196,1198],{"class":226,"line":534},[224,1176,1177],{"class":304},"  console",[224,1179,241],{"class":240},[224,1181,332],{"class":300},[224,1183,305],{"class":253},[224,1185,1030],{"class":300},[224,1187,305],{"class":253},[224,1189,1190],{"class":1035},"3",[224,1192,485],{"class":240},[224,1194,1195],{"class":1035}," 4",[224,1197,1044],{"class":253},[224,1199,423],{"class":240},[224,1201,1202,1205,1208,1210],{"class":226,"line":539},[224,1203,1204],{"class":240},"},",[224,1206,1207],{"class":1035}," 1000",[224,1209,315],{"class":304},[224,1211,423],{"class":240},[56,1213,1215],{"id":1214},"_3-esm-与-commonjs-的重要差异","3. ESM 与 CommonJS 的重要差异",[1217,1218,1219,1235],"table",{},[1220,1221,1222],"thead",{},[1223,1224,1225,1229,1232],"tr",{},[1226,1227,1228],"th",{},"特性",[1226,1230,1231],{},"CommonJS",[1226,1233,1234],{},"ESM",[1236,1237,1238,1260,1273,1289,1302,1329,1347],"tbody",{},[1223,1239,1240,1246,1254],{},[1241,1242,1243],"td",{},[66,1244,1245],{},"语法",[1241,1247,1248,1251,1252],{},[32,1249,1250],{},"require()"," \u002F ",[32,1253,50],{},[1241,1255,1256,1251,1258],{},[32,1257,820],{},[32,1259,824],{},[1223,1261,1262,1267,1270],{},[1241,1263,1264],{},[66,1265,1266],{},"加载时机",[1241,1268,1269],{},"同步，运行时加载",[1241,1271,1272],{},"异步，编译时静态分析（但支持动态导入）",[1223,1274,1275,1283,1286],{},[1241,1276,1277],{},[66,1278,1279,1280],{},"顶级 ",[32,1281,1282],{},"await",[1241,1284,1285],{},"❌ 不支持",[1241,1287,1288],{},"✅ 支持（仅在 ESM 中）",[1223,1290,1291,1296,1299],{},[1241,1292,1293],{},[66,1294,1295],{},"循环依赖处理",[1241,1297,1298],{},"返回部分导出（有限加载）",[1241,1300,1301],{},"通过“绑定”机制，但需谨慎使用",[1223,1303,1304,1309,1322],{},[1241,1305,1306],{},[66,1307,1308],{},"模块作用域",[1241,1310,1311,1312,90,1314,90,1316,90,1318,90,1320],{},"拥有 ",[32,1313,198],{},[32,1315,195],{},[32,1317,34],{},[32,1319,13],{},[32,1321,164],{},[1241,1323,1324,1325,1328],{},"没有这些变量，需通过 ",[32,1326,1327],{},"import.meta.url"," 获取",[1223,1330,1331,1336,1340],{},[1241,1332,1333],{},[66,1334,1335],{},"缓存",[1241,1337,1338],{},[32,1339,360],{},[1241,1341,1342,1343,1346],{},"基于 URL 的缓存，可通过 ",[32,1344,1345],{},"import.meta.resolve"," 等操作",[1223,1348,1349,1354,1365],{},[1241,1350,1351],{},[66,1352,1353],{},"文件扩展名",[1241,1355,1356,90,1358,1360,1361,1364],{},[32,1357,109],{},[32,1359,868],{},"（当 ",[32,1362,1363],{},"type: commonjs","）",[1241,1366,1367,90,1369,1360,1371,1364],{},[32,1368,845],{},[32,1370,109],{},[32,1372,1373],{},"type: module",[41,1375,1377],{"id":1376},"三commonjs-与-esm-的互操作","三、CommonJS 与 ESM 的互操作",[28,1379,1380],{},"在实际项目中，经常需要混合使用两种模块格式。Node.js 提供了一套复杂的互操作规则。",[56,1382,1384],{"id":1383},"_1-在-esm-中导入-commonjs-模块","1. 在 ESM 中导入 CommonJS 模块",[71,1386,1387,1400,1413],{},[74,1388,1389,1392,1393,1396,1397,1399],{},[66,1390,1391],{},"默认导入","：可以使用 ",[32,1394,1395],{},"import module from 'cjs-module'","，Node.js 会自动将 ",[32,1398,50],{}," 视为默认导出。",[74,1401,1402,69,1405,1408,1409,1412],{},[66,1403,1404],{},"命名空间导入",[32,1406,1407],{},"import * as cjs from 'cjs-module'","，得到的是包含 ",[32,1410,1411],{},"default"," 属性以及其他命名属性的对象（因为 CommonJS 的导出没有作为命名导出）。",[74,1414,1415,1418,1419,1422],{},[66,1416,1417],{},"仅导入命名导出","：不能直接使用 ",[32,1420,1421],{},"import { prop } from 'cjs-module'","，除非该 CommonJS 模块使用了静态可分析的导出（某些工具可协助，但原生不支持）。",[28,1424,1425,69],{},[66,1426,213],{},[215,1428,1430],{"className":217,"code":1429,"language":219,"meta":220,"style":220},"\u002F\u002F commonjs.cjs\nmodule.exports = { name: \"Alice\", age: 25 };\n\n\u002F\u002F esm.mjs\nimport cjs from \".\u002Fcommonjs.cjs\";\nconsole.log(cjs.name); \u002F\u002F 'Alice'\n\nimport * as wrapped from \".\u002Fcommonjs.cjs\";\nconsole.log(wrapped.default.name); \u002F\u002F 'Alice'\n",[32,1431,1432,1437,1473,1477,1482,1501,1522,1526,1549],{"__ignoreMap":220},[224,1433,1434],{"class":226,"line":227},[224,1435,1436],{"class":230},"\u002F\u002F commonjs.cjs\n",[224,1438,1439,1441,1443,1445,1447,1449,1452,1454,1456,1459,1461,1463,1466,1468,1471],{"class":226,"line":234},[224,1440,13],{"class":237},[224,1442,241],{"class":240},[224,1444,164],{"class":237},[224,1446,247],{"class":246},[224,1448,250],{"class":240},[224,1450,1451],{"class":253}," name",[224,1453,257],{"class":240},[224,1455,261],{"class":260},[224,1457,1458],{"class":264},"Alice",[224,1460,268],{"class":260},[224,1462,485],{"class":240},[224,1464,1465],{"class":253}," age",[224,1467,257],{"class":240},[224,1469,1470],{"class":1035}," 25",[224,1472,271],{"class":240},[224,1474,1475],{"class":226,"line":274},[224,1476,278],{"emptyLinePlaceholder":277},[224,1478,1479],{"class":226,"line":281},[224,1480,1481],{"class":230},"\u002F\u002F esm.mjs\n",[224,1483,1484,1486,1489,1492,1494,1497,1499],{"class":226,"line":287},[224,1485,820],{"class":951},[224,1487,1488],{"class":304}," cjs ",[224,1490,1491],{"class":951},"from",[224,1493,261],{"class":260},[224,1495,1496],{"class":264},".\u002Fcommonjs.cjs",[224,1498,268],{"class":260},[224,1500,423],{"class":240},[224,1502,1503,1505,1507,1509,1512,1514,1517,1519],{"class":226,"line":324},[224,1504,327],{"class":304},[224,1506,241],{"class":240},[224,1508,332],{"class":300},[224,1510,1511],{"class":304},"(cjs",[224,1513,241],{"class":240},[224,1515,1516],{"class":304},"name)",[224,1518,318],{"class":240},[224,1520,1521],{"class":230}," \u002F\u002F 'Alice'\n",[224,1523,1524],{"class":226,"line":512},[224,1525,278],{"emptyLinePlaceholder":277},[224,1527,1528,1530,1533,1536,1539,1541,1543,1545,1547],{"class":226,"line":534},[224,1529,820],{"class":951},[224,1531,1532],{"class":237}," *",[224,1534,1535],{"class":951}," as",[224,1537,1538],{"class":304}," wrapped ",[224,1540,1491],{"class":951},[224,1542,261],{"class":260},[224,1544,1496],{"class":264},[224,1546,268],{"class":260},[224,1548,423],{"class":240},[224,1550,1551,1553,1555,1557,1560,1562,1564,1566,1568,1570],{"class":226,"line":539},[224,1552,327],{"class":304},[224,1554,241],{"class":240},[224,1556,332],{"class":300},[224,1558,1559],{"class":304},"(wrapped",[224,1561,241],{"class":240},[224,1563,1411],{"class":304},[224,1565,241],{"class":240},[224,1567,1516],{"class":304},[224,1569,318],{"class":240},[224,1571,1521],{"class":230},[28,1573,1574,1577,1578,1580],{},[66,1575,1576],{},"注意","：ESM 中导入 CommonJS 模块时，",[32,1579,34],{}," 的同步特性会导致 ESM 依赖树在解析阶段同步执行模块代码，但整体仍然是异步的。",[56,1582,1584],{"id":1583},"_2-在-commonjs-中导入-esm-模块","2. 在 CommonJS 中导入 ESM 模块",[28,1586,1587,1588,1590,1591,1594,1595,1597,1598,1600],{},"早期 Node.js 中，CommonJS 不能直接 ",[32,1589,34],{}," 一个 ES 模块（会抛出 ",[32,1592,1593],{},"ERR_REQUIRE_ESM","），必须使用动态 ",[32,1596,1053],{},"（返回 Promise，需在回调或 ",[32,1599,1135],{}," 函数中处理）：",[215,1602,1604],{"className":217,"code":1603,"language":219,"meta":220,"style":220},"\u002F\u002F esm.mjs\nexport const greet = () => \"Hello\";\n\n\u002F\u002F commonjs.cjs\nasync function load() {\n  const { greet } = await import(\".\u002Fesm.mjs\");\n  console.log(greet());\n}\nload();\n",[32,1605,1606,1610,1634,1638,1642,1657,1686,1704,1708],{"__ignoreMap":220},[224,1607,1608],{"class":226,"line":227},[224,1609,1481],{"class":230},[224,1611,1612,1614,1616,1619,1621,1623,1625,1627,1630,1632],{"class":226,"line":234},[224,1613,824],{"class":951},[224,1615,954],{"class":290},[224,1617,1618],{"class":957}," greet",[224,1620,247],{"class":246},[224,1622,1138],{"class":240},[224,1624,975],{"class":290},[224,1626,261],{"class":260},[224,1628,1629],{"class":264},"Hello",[224,1631,268],{"class":260},[224,1633,423],{"class":240},[224,1635,1636],{"class":226,"line":274},[224,1637,278],{"emptyLinePlaceholder":277},[224,1639,1640],{"class":226,"line":281},[224,1641,1436],{"class":230},[224,1643,1644,1646,1649,1652,1655],{"class":226,"line":287},[224,1645,1135],{"class":290},[224,1647,1648],{"class":290}," function",[224,1650,1651],{"class":300}," load",[224,1653,1654],{"class":240},"()",[224,1656,1143],{"class":240},[224,1658,1659,1661,1663,1665,1667,1669,1671,1673,1675,1677,1680,1682,1684],{"class":226,"line":324},[224,1660,1148],{"class":290},[224,1662,250],{"class":240},[224,1664,1618],{"class":294},[224,1666,1005],{"class":240},[224,1668,247],{"class":246},[224,1670,1081],{"class":951},[224,1672,1084],{"class":246},[224,1674,305],{"class":253},[224,1676,268],{"class":260},[224,1678,1679],{"class":264},".\u002Fesm.mjs",[224,1681,268],{"class":260},[224,1683,315],{"class":253},[224,1685,423],{"class":240},[224,1687,1688,1690,1692,1694,1696,1699,1702],{"class":226,"line":512},[224,1689,1177],{"class":304},[224,1691,241],{"class":240},[224,1693,332],{"class":300},[224,1695,305],{"class":253},[224,1697,1698],{"class":300},"greet",[224,1700,1701],{"class":253},"())",[224,1703,423],{"class":240},[224,1705,1706],{"class":226,"line":534},[224,1707,932],{"class":240},[224,1709,1710,1713,1715],{"class":226,"line":539},[224,1711,1712],{"class":300},"load",[224,1714,1654],{"class":304},[224,1716,423],{"class":240},[28,1718,1719,1722,1723,1726,1727,1730,1731,1733,1734,1736,1737,1739],{},[66,1720,1721],{},"版本更新","：自 Node.js v22.12.0 \u002F v20.19.0 起，",[32,1724,1725],{},"require(esm)"," 已默认启用并趋于稳定——只要目标 ES 模块是",[66,1728,1729],{},"同步","的（不含顶层 ",[32,1732,1282],{},"），",[32,1735,1250],{}," 就可以直接加载它，返回的对象类似 ",[32,1738,1053],{}," 得到的模块命名空间对象：",[215,1741,1743],{"className":217,"code":1742,"language":219,"meta":220,"style":220},"\u002F\u002F esm.mjs（同步、无顶层 await）\nexport const greet = () => \"Hello\";\n\n\u002F\u002F commonjs.cjs\nconst { greet } = require(\".\u002Fesm.mjs\"); \u002F\u002F Node 22.12+\u002F20.19+ 可直接同步 require\nconsole.log(greet());\n",[32,1744,1745,1750,1772,1776,1780,1809],{"__ignoreMap":220},[224,1746,1747],{"class":226,"line":227},[224,1748,1749],{"class":230},"\u002F\u002F esm.mjs（同步、无顶层 await）\n",[224,1751,1752,1754,1756,1758,1760,1762,1764,1766,1768,1770],{"class":226,"line":234},[224,1753,824],{"class":951},[224,1755,954],{"class":290},[224,1757,1618],{"class":957},[224,1759,247],{"class":246},[224,1761,1138],{"class":240},[224,1763,975],{"class":290},[224,1765,261],{"class":260},[224,1767,1629],{"class":264},[224,1769,268],{"class":260},[224,1771,423],{"class":240},[224,1773,1774],{"class":226,"line":274},[224,1775,278],{"emptyLinePlaceholder":277},[224,1777,1778],{"class":226,"line":281},[224,1779,1436],{"class":230},[224,1781,1782,1784,1786,1788,1790,1792,1794,1796,1798,1800,1802,1804,1806],{"class":226,"line":287},[224,1783,291],{"class":290},[224,1785,250],{"class":240},[224,1787,1618],{"class":294},[224,1789,1005],{"class":240},[224,1791,247],{"class":246},[224,1793,301],{"class":300},[224,1795,305],{"class":304},[224,1797,268],{"class":260},[224,1799,1679],{"class":264},[224,1801,268],{"class":260},[224,1803,315],{"class":304},[224,1805,318],{"class":240},[224,1807,1808],{"class":230}," \u002F\u002F Node 22.12+\u002F20.19+ 可直接同步 require\n",[224,1810,1811,1813,1815,1817,1819,1821,1823],{"class":226,"line":324},[224,1812,327],{"class":304},[224,1814,241],{"class":240},[224,1816,332],{"class":300},[224,1818,305],{"class":304},[224,1820,1698],{"class":300},[224,1822,1701],{"class":304},[224,1824,423],{"class":240},[28,1826,1827,1828,1830,1831,1833,1834,1837,1838,125],{},"若目标 ES 模块包含顶层 ",[32,1829,1282],{},"，",[32,1832,1250],{}," 仍会抛出 ",[32,1835,1836],{},"ERR_REQUIRE_ASYNC_MODULE","，此时依然需要动态 ",[32,1839,1053],{},[56,1841,1843],{"id":1842},"_3-互操作注意事项","3. 互操作注意事项",[71,1845,1846,1865,1878],{},[74,1847,1848,1851,1852,1854,1855,1857,1858,1861,1862,1864],{},[66,1849,1850],{},"“默认导出”的差异","：CommonJS 模块没有真正的默认导出，其 ",[32,1853,50],{}," 整体被视为 ESM 中的 ",[32,1856,1411],{},"。因此 ESM 中 ",[32,1859,1860],{},"import cjs from 'cjs'"," 相当于拿到了整个 ",[32,1863,50],{}," 对象。",[74,1866,1867,1870,1871,90,1874,1877],{},[66,1868,1869],{},"命名导出的缺失","：CommonJS 模块的命名属性不会自动成为 ESM 的命名导出。若需要，可以使用工具（如 ",[32,1872,1873],{},"esbuild",[32,1875,1876],{},"@babel\u002Fnode","）或在导出时手动包装。",[74,1879,1880,1883],{},[66,1881,1882],{},"循环依赖","：ESM 的循环依赖比 CommonJS 更安全，因为 ESM 会创建“实时绑定”。但在混合使用时，循环依赖可能导致难以预测的行为，应尽量避免。",[23,1885,1886],{"id":1886},"总结对比表",[1217,1888,1889,1900],{},[1220,1890,1891],{},[1223,1892,1893,1896,1898],{},[1226,1894,1895],{},"方面",[1226,1897,1231],{},[1226,1899,1234],{},[1236,1901,1902,1923,1940,1964,1977,1989,2002,2015],{},[1223,1903,1904,1909,1916],{},[1241,1905,1906],{},[66,1907,1908],{},"默认扩展名",[1241,1910,1911,90,1913,1915],{},[32,1912,109],{},[32,1914,868],{},"（当 package.json 未指定 type 或 type: commonjs）",[1241,1917,1918,90,1920,1922],{},[32,1919,845],{},[32,1921,109],{},"（当 type: module）",[1223,1924,1925,1930,1935],{},[1241,1926,1927],{},[66,1928,1929],{},"导入语句",[1241,1931,1932],{},[32,1933,1934],{},"const lib = require('lib')",[1241,1936,1937],{},[32,1938,1939],{},"import lib from 'lib'",[1223,1941,1942,1947,1956],{},[1241,1943,1944],{},[66,1945,1946],{},"导出语句",[1241,1948,1949,1952,1953],{},[32,1950,1951],{},"module.exports = ..."," 或 ",[32,1954,1955],{},"exports.foo = ...",[1241,1957,1958,1952,1961],{},[32,1959,1960],{},"export default ...",[32,1962,1963],{},"export const foo = ...",[1223,1965,1966,1971,1974],{},[1241,1967,1968],{},[66,1969,1970],{},"加载方式",[1241,1972,1973],{},"同步、运行时",[1241,1975,1976],{},"异步、编译时 + 运行时（动态 import）",[1223,1978,1979,1983,1986],{},[1241,1980,1981],{},[66,1982,1882],{},[1241,1984,1985],{},"返回已执行部分导出",[1241,1987,1988],{},"实时绑定，但依赖图必须可解析",[1223,1990,1991,1996,1999],{},[1241,1992,1993],{},[66,1994,1995],{},"静态分析",[1241,1997,1998],{},"困难（动态 require）",[1241,2000,2001],{},"容易（import\u002Fexport 静态）",[1223,2003,2004,2009,2012],{},[1241,2005,2006],{},[66,2007,2008],{},"顶级 await",[1241,2010,2011],{},"❌",[1241,2013,2014],{},"✅",[1223,2016,2017,2022,2030],{},[1241,2018,2019],{},[66,2020,2021],{},"与 ESM 互操作",[1241,2023,2024,2025,2027,2028],{},"Node 22.12+\u002F20.19+ 可 ",[32,2026,1250],{}," 同步 ESM（不含顶层 await）；更早版本需动态 ",[32,2029,1053],{},[1241,2031,2032],{},"可以同步导入 CommonJS（整体作为 default）",[23,2034,2035],{"id":2035},"推荐参考资料",[71,2037,2038,2054,2064,2070],{},[74,2039,2040,69,2043,90,2049],{},[66,2041,2042],{},"Node.js 官方文档",[800,2044,2048],{"href":2045,"rel":2046},"https:\u002F\u002Fnodejs.org\u002Fapi\u002Fmodules.html",[2047],"nofollow","Modules: CommonJS modules",[800,2050,2053],{"href":2051,"rel":2052},"https:\u002F\u002Fnodejs.org\u002Fapi\u002Fesm.html",[2047],"Modules: ECMAScript modules",[74,2055,2056,69,2059],{},[66,2057,2058],{},"Node.js 官方指南",[800,2060,2063],{"href":2061,"rel":2062},"https:\u002F\u002Fnodejs.org\u002Fapi\u002Fesm.html#differences-between-es-modules-and-commonjs",[2047],"ESM 与 CommonJS 的差异",[74,2065,2066,2069],{},[66,2067,2068],{},"深入理解","：《Node.js 设计模式》第 1 章（模块系统）",[74,2071,2072,69,2075,90,2077,2079],{},[66,2073,2074],{},"工具",[32,2076,1873],{},[32,2078,1876],{}," 可用于转换模块格式",[28,2081,2082],{},"理解模块系统是编写可维护、可扩展 Node.js 应用的基础，尤其是在大型项目中，合理选择模块格式并遵循互操作规则至关重要。",[2084,2085,2086],"style",{},"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 pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sseR_, html code.shiki .sseR_{--shiki-light:#9C3EDA;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .srjyR, html code.shiki .srjyR{--shiki-light:#90A4AE;--shiki-light-font-style:inherit;--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}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 .sfCm-, html code.shiki .sfCm-{--shiki-light:#90A4AE;--shiki-default:#6F42C1;--shiki-dark:#B392F0}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 .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":220,"searchDepth":234,"depth":234,"links":2088},[2089,2094,2095],{"id":25,"depth":234,"text":26,"children":2090},[2091,2092,2093],{"id":43,"depth":274,"text":44},{"id":813,"depth":274,"text":814},{"id":1376,"depth":274,"text":1377},{"id":1886,"depth":234,"text":1886},{"id":2035,"depth":234,"text":2035},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fend\u002FNodeJs\u002Fbase\u002Fmodule","knowledge\u002Fknowledge\u002Fbooklet\u002Fend\u002FNodeJs\u002Fbase\u002Fmodule.md","md",{"items":2101},[2102,2106,2110,2114,2118,2122],{"path":2103,"title":2104,"description":2105,"category":10,"score":324},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fbase\u002Fvar","全局对象与变量","Node.js 提供模块内可直接使用的全局对象；与浏览器 window 不同，模块顶层的 const\u002Flet 不会挂到 global。见 后端入门概览、模块系统。",{"path":2107,"title":2108,"description":2109,"category":10,"score":324},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fbase\u002Fevent-loop","事件循环","Node.js 的事件循环是其实现非阻塞 I\u002FO 的核心机制。它基于 libuv 库，将各种异步操作（定时器、I\u002FO、setImmediate 等）组织成不同的阶段，每个阶段都有一个先进先出的回调队列。事件循环会按照固定的顺序反复执行…",{"path":2111,"title":2112,"description":2113,"category":10,"score":324},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fbase\u002Fevent","事件驱动与非阻塞 I\u002FO 模型","Node.js 的底层架构核心是事件驱动与非阻塞 I\u002FO：以 V8 引擎执行 JavaScript、libuv 库处理底层 I\u002FO 与事件循环。涵盖 libuv 线程池、事件循环各阶段、EventEmitter 实践、最佳实践与常见坑。",{"path":2115,"title":2116,"description":2117,"category":10,"score":281},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fbasics","后端入门概览","本目录覆盖 JavaScript\u002FTypeScript 服务端运行时与框架、数据存储，以及 Rust 系统编程入门，提供从零到部署的完整学习路径。前置建议：JavaScript 基础、工程化 · 环境变量。",{"path":2119,"title":2120,"description":2121,"category":10,"score":281},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Ffs","文件系统","Node.js 的 fs 模块提供了与文件系统交互的 API，几乎涵盖了所有标准文件操作。它支持三种风格的 API：同步、回调式异步 和 Promise 式异步。下面详细介绍这些 API 的选择策略、流式读写、文件监视以及常用操作。",{"path":2123,"title":2124,"description":2125,"category":10,"score":281},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fasync","异步编程与模式","Node.js 的核心优势在于异步非阻塞 I\u002FO，但这也带来了回调地狱、错误处理复杂等问题。下面从解救方案、工具函数、并发控制、异步迭代以及常见反模式等角度展开。",{"series":2127,"title":2128,"items":2129,"index":234,"prev":2137,"next":2138},"booklet\u002Fend\u002Fnodejs\u002Fbase","base",[2130,2132,2134,2135],{"path":2111,"title":2112,"date":2131,"pinned":15},"2020-06-20",{"path":2107,"title":2108,"date":2133,"pinned":15},"2024-11-20",{"path":7,"title":8,"date":14,"pinned":15},{"path":2103,"title":2104,"date":2136,"pinned":15},"2025-01-03",{"path":2107,"title":2108,"date":2133,"pinned":15},{"path":2103,"title":2104,"date":2136,"pinned":15}]