[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fstream":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fstream":2807,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fstream":2833},{"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":2803,"stem":2804,"id":2805,"extension":2806},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fstream","流","流是 Node.js 中处理有序数据的抽象接口，用于以连续方式异步读取或写入数据。它们特别适合处理大文件、网络通信或任何可能无限产生的数据。Node.js 内置的 stream 模块提供了四种基本流类型，以及用于组合和错误处理的工具函数。","技能小册",[12,13],"nodejs","stream","2022-05-03",false,{"type":17,"value":18,"toc":2789},"minimark",[19,22,27,40,45,160,164,559,570,574,581,628,635,642,767,775,782,1022,1026,1029,1033,1047,1323,1327,1336,1538,1542,1552,1719,1723,1737,1749,1756,1759,1945,1950,1953,2142,2150,2165,2169,2177,2449,2454,2458,2469,2653,2656,2732,2737,2759,2762,2785],[20,21,8],"h1",{"id":8},[23,24,26],"h2",{"id":25},"nodejs-流stream详解","Node.js 流（Stream）详解",[28,29,30,31,35,36,39],"p",{},"流是 Node.js 中处理",[32,33,34],"strong",{},"有序数据","的抽象接口，用于以连续方式异步读取或写入数据。它们特别适合处理大文件、网络通信或任何可能无限产生的数据。Node.js 内置的 ",[37,38,13],"code",{}," 模块提供了四种基本流类型，以及用于组合和错误处理的工具函数。",[41,42,44],"h3",{"id":43},"一流的四种基本类型","一、流的四种基本类型",[46,47,48,67],"table",{},[49,50,51],"thead",{},[52,53,54,58,61,64],"tr",{},[55,56,57],"th",{},"类型",[55,59,60],{},"描述",[55,62,63],{},"方向",[55,65,66],{},"典型应用",[68,69,70,94,116,138],"tbody",{},[52,71,72,79,82,85],{},[73,74,75,78],"td",{},[32,76,77],{},"可读流"," (Readable)",[73,80,81],{},"数据可以从中读取",[73,83,84],{},"单向：流出",[73,86,87,90,91],{},[37,88,89],{},"fs.createReadStream","、",[37,92,93],{},"http.IncomingMessage",[52,95,96,102,105,108],{},[73,97,98,101],{},[32,99,100],{},"可写流"," (Writable)",[73,103,104],{},"数据可以写入其中",[73,106,107],{},"单向：流入",[73,109,110,90,113],{},[37,111,112],{},"fs.createWriteStream",[37,114,115],{},"http.ServerResponse",[52,117,118,124,127,130],{},[73,119,120,123],{},[32,121,122],{},"双工流"," (Duplex)",[73,125,126],{},"既可读又可写",[73,128,129],{},"双向独立",[73,131,132,90,135],{},[37,133,134],{},"net.Socket",[37,136,137],{},"crypto.createCipheriv",[52,139,140,146,149,152],{},[73,141,142,145],{},[32,143,144],{},"转换流"," (Transform)",[73,147,148],{},"双工流的一种，会对数据进行转换",[73,150,151],{},"双向且数据经过处理",[73,153,154,90,157],{},[37,155,156],{},"zlib.createGzip",[37,158,159],{},"crypto.createHash",[161,162,163],"h4",{"id":163},"示例代码",[165,166,171],"pre",{"className":167,"code":168,"language":169,"meta":170,"style":170},"language-js shiki shiki-themes material-theme-lighter github-light github-dark","const { Readable, Writable, Duplex, Transform } = require(\"stream\");\n\n\u002F\u002F 可读流\nconst readable = Readable.from([\"Hello\", \"World\"]);\n\n\u002F\u002F 可写流\nconst writable = fs.createWriteStream(\".\u002Foutput.txt\");\n\n\u002F\u002F 双工流\nconst duplex = new Duplex({\n    read(size) {\n        \u002F* 实现读 *\u002F\n    },\n    write(chunk, encoding, callback) {\n        \u002F* 实现写 *\u002F\n    },\n});\n\n\u002F\u002F 转换流（大小写转换）\nconst transform = new Transform({\n    transform(chunk, encoding, callback) {\n        const output = chunk.toString().toUpperCase();\n        callback(null, output);\n    },\n});\n","js","",[37,172,173,236,243,250,293,298,304,335,340,346,366,384,390,396,421,427,432,442,447,453,471,493,525,545,550],{"__ignoreMap":170},[174,175,178,182,186,190,193,196,198,201,203,206,209,213,217,221,225,228,230,233],"span",{"class":176,"line":177},"line",1,[174,179,181],{"class":180},"sbsja","const",[174,183,185],{"class":184},"sP7_E"," {",[174,187,189],{"class":188},"s_hVV"," Readable",[174,191,192],{"class":184},",",[174,194,195],{"class":188}," Writable",[174,197,192],{"class":184},[174,199,200],{"class":188}," Duplex",[174,202,192],{"class":184},[174,204,205],{"class":188}," Transform",[174,207,208],{"class":184}," }",[174,210,212],{"class":211},"smGrS"," =",[174,214,216],{"class":215},"sGLFI"," require",[174,218,220],{"class":219},"su5hD","(",[174,222,224],{"class":223},"sjJ54","\"",[174,226,13],{"class":227},"s_sjI",[174,229,224],{"class":223},[174,231,232],{"class":219},")",[174,234,235],{"class":184},";\n",[174,237,239],{"class":176,"line":238},2,[174,240,242],{"emptyLinePlaceholder":241},true,"\n",[174,244,246],{"class":176,"line":245},3,[174,247,249],{"class":248},"sutJx","\u002F\u002F 可读流\n",[174,251,253,255,258,260,262,265,268,271,273,276,278,280,283,286,288,291],{"class":176,"line":252},4,[174,254,181],{"class":180},[174,256,257],{"class":188}," readable",[174,259,212],{"class":211},[174,261,189],{"class":219},[174,263,264],{"class":184},".",[174,266,267],{"class":215},"from",[174,269,270],{"class":219},"([",[174,272,224],{"class":223},[174,274,275],{"class":227},"Hello",[174,277,224],{"class":223},[174,279,192],{"class":184},[174,281,282],{"class":223}," \"",[174,284,285],{"class":227},"World",[174,287,224],{"class":223},[174,289,290],{"class":219},"])",[174,292,235],{"class":184},[174,294,296],{"class":176,"line":295},5,[174,297,242],{"emptyLinePlaceholder":241},[174,299,301],{"class":176,"line":300},6,[174,302,303],{"class":248},"\u002F\u002F 可写流\n",[174,305,307,309,312,314,317,319,322,324,326,329,331,333],{"class":176,"line":306},7,[174,308,181],{"class":180},[174,310,311],{"class":188}," writable",[174,313,212],{"class":211},[174,315,316],{"class":219}," fs",[174,318,264],{"class":184},[174,320,321],{"class":215},"createWriteStream",[174,323,220],{"class":219},[174,325,224],{"class":223},[174,327,328],{"class":227},".\u002Foutput.txt",[174,330,224],{"class":223},[174,332,232],{"class":219},[174,334,235],{"class":184},[174,336,338],{"class":176,"line":337},8,[174,339,242],{"emptyLinePlaceholder":241},[174,341,343],{"class":176,"line":342},9,[174,344,345],{"class":248},"\u002F\u002F 双工流\n",[174,347,349,351,354,356,359,361,363],{"class":176,"line":348},10,[174,350,181],{"class":180},[174,352,353],{"class":188}," duplex",[174,355,212],{"class":211},[174,357,358],{"class":211}," new",[174,360,200],{"class":215},[174,362,220],{"class":219},[174,364,365],{"class":184},"{\n",[174,367,369,373,375,379,381],{"class":176,"line":368},11,[174,370,372],{"class":371},"sVXei","    read",[174,374,220],{"class":184},[174,376,378],{"class":377},"s99_P","size",[174,380,232],{"class":184},[174,382,383],{"class":184}," {\n",[174,385,387],{"class":176,"line":386},12,[174,388,389],{"class":248},"        \u002F* 实现读 *\u002F\n",[174,391,393],{"class":176,"line":392},13,[174,394,395],{"class":184},"    },\n",[174,397,399,402,404,407,409,412,414,417,419],{"class":176,"line":398},14,[174,400,401],{"class":371},"    write",[174,403,220],{"class":184},[174,405,406],{"class":377},"chunk",[174,408,192],{"class":184},[174,410,411],{"class":377}," encoding",[174,413,192],{"class":184},[174,415,416],{"class":377}," callback",[174,418,232],{"class":184},[174,420,383],{"class":184},[174,422,424],{"class":176,"line":423},15,[174,425,426],{"class":248},"        \u002F* 实现写 *\u002F\n",[174,428,430],{"class":176,"line":429},16,[174,431,395],{"class":184},[174,433,435,438,440],{"class":176,"line":434},17,[174,436,437],{"class":184},"}",[174,439,232],{"class":219},[174,441,235],{"class":184},[174,443,445],{"class":176,"line":444},18,[174,446,242],{"emptyLinePlaceholder":241},[174,448,450],{"class":176,"line":449},19,[174,451,452],{"class":248},"\u002F\u002F 转换流（大小写转换）\n",[174,454,456,458,461,463,465,467,469],{"class":176,"line":455},20,[174,457,181],{"class":180},[174,459,460],{"class":188}," transform",[174,462,212],{"class":211},[174,464,358],{"class":211},[174,466,205],{"class":215},[174,468,220],{"class":219},[174,470,365],{"class":184},[174,472,474,477,479,481,483,485,487,489,491],{"class":176,"line":473},21,[174,475,476],{"class":371},"    transform",[174,478,220],{"class":184},[174,480,406],{"class":377},[174,482,192],{"class":184},[174,484,411],{"class":377},[174,486,192],{"class":184},[174,488,416],{"class":377},[174,490,232],{"class":184},[174,492,383],{"class":184},[174,494,496,499,502,504,507,509,512,516,518,521,523],{"class":176,"line":495},22,[174,497,498],{"class":180},"        const",[174,500,501],{"class":188}," output",[174,503,212],{"class":211},[174,505,506],{"class":219}," chunk",[174,508,264],{"class":184},[174,510,511],{"class":215},"toString",[174,513,515],{"class":514},"skxfh","()",[174,517,264],{"class":184},[174,519,520],{"class":215},"toUpperCase",[174,522,515],{"class":514},[174,524,235],{"class":184},[174,526,528,531,533,537,539,541,543],{"class":176,"line":527},23,[174,529,530],{"class":215},"        callback",[174,532,220],{"class":514},[174,534,536],{"class":535},"s39Yj","null",[174,538,192],{"class":184},[174,540,501],{"class":219},[174,542,232],{"class":514},[174,544,235],{"class":184},[174,546,548],{"class":176,"line":547},24,[174,549,395],{"class":184},[174,551,553,555,557],{"class":176,"line":552},25,[174,554,437],{"class":184},[174,556,232],{"class":219},[174,558,235],{"class":184},[41,560,562,563,566,567],{"id":561},"二背压机制与-pipe-pipeline","二、背压机制与 ",[37,564,565],{},"pipe"," \u002F ",[37,568,569],{},"pipeline",[161,571,573],{"id":572},"_1-背压机制backpressure","1. 背压机制（Backpressure）",[28,575,576,577,580],{},"当可读流的数据产生速度超过可写流的消费速度时，数据会在内部缓冲区累积。背压机制通过",[32,578,579],{},"控制数据流动","来防止内存溢出：",[582,583,584,600,616],"ul",{},[585,586,587,588,591,592,595,596,599],"li",{},"可读流有一个内部 ",[37,589,590],{},"highWaterMark","（默认 16KB）。当缓冲区大小超过该值，",[37,593,594],{},"readable.push()"," 返回 ",[37,597,598],{},"false","，表示应暂停读取。",[585,601,602,603,605,606,595,609,611,612,615],{},"可写流也有 ",[37,604,590],{},"，当写入速度慢时，",[37,607,608],{},"writable.write()",[37,610,598],{},"，并触发 ",[37,613,614],{},"drain"," 事件。",[585,617,618,619,621,622,624,625,627],{},"在 ",[37,620,565],{}," 或 ",[37,623,569],{}," 中，背压自动处理；手动实现时需要检查返回值并监听 ",[37,626,614],{},"。",[161,629,631,632],{"id":630},"_2-readablepipewritable","2. ",[37,633,634],{},"readable.pipe(writable)",[28,636,637,638,641],{},"最简单的管道方式，自动处理背压和结束事件。缺点：错误处理不完善（需要单独监听 ",[37,639,640],{},"error"," 事件）。",[165,643,645],{"className":167,"code":644,"language":169,"meta":170,"style":170},"const readStream = fs.createReadStream(\"bigfile.txt\");\nconst writeStream = fs.createWriteStream(\"copy.txt\");\nreadStream.pipe(writeStream);\nwriteStream.on(\"finish\", () => console.log(\"复制完成\"));\n",[37,646,647,676,704,718],{"__ignoreMap":170},[174,648,649,651,654,656,658,660,663,665,667,670,672,674],{"class":176,"line":177},[174,650,181],{"class":180},[174,652,653],{"class":188}," readStream",[174,655,212],{"class":211},[174,657,316],{"class":219},[174,659,264],{"class":184},[174,661,662],{"class":215},"createReadStream",[174,664,220],{"class":219},[174,666,224],{"class":223},[174,668,669],{"class":227},"bigfile.txt",[174,671,224],{"class":223},[174,673,232],{"class":219},[174,675,235],{"class":184},[174,677,678,680,683,685,687,689,691,693,695,698,700,702],{"class":176,"line":238},[174,679,181],{"class":180},[174,681,682],{"class":188}," writeStream",[174,684,212],{"class":211},[174,686,316],{"class":219},[174,688,264],{"class":184},[174,690,321],{"class":215},[174,692,220],{"class":219},[174,694,224],{"class":223},[174,696,697],{"class":227},"copy.txt",[174,699,224],{"class":223},[174,701,232],{"class":219},[174,703,235],{"class":184},[174,705,706,709,711,713,716],{"class":176,"line":245},[174,707,708],{"class":219},"readStream",[174,710,264],{"class":184},[174,712,565],{"class":215},[174,714,715],{"class":219},"(writeStream)",[174,717,235],{"class":184},[174,719,720,723,725,728,730,732,735,737,739,742,745,748,750,753,755,757,760,762,765],{"class":176,"line":252},[174,721,722],{"class":219},"writeStream",[174,724,264],{"class":184},[174,726,727],{"class":215},"on",[174,729,220],{"class":219},[174,731,224],{"class":223},[174,733,734],{"class":227},"finish",[174,736,224],{"class":223},[174,738,192],{"class":184},[174,740,741],{"class":184}," ()",[174,743,744],{"class":180}," =>",[174,746,747],{"class":219}," console",[174,749,264],{"class":184},[174,751,752],{"class":215},"log",[174,754,220],{"class":219},[174,756,224],{"class":223},[174,758,759],{"class":227},"复制完成",[174,761,224],{"class":223},[174,763,764],{"class":219},"))",[174,766,235],{"class":184},[161,768,770,771,774],{"id":769},"_3-streampipeline推荐","3. ",[37,772,773],{},"stream.pipeline","（推荐）",[28,776,777,778,781],{},"从 Node.js 10 开始引入，支持 ",[37,779,780],{},"Promise"," 并自动清理流、转发错误，避免内存泄漏。",[165,783,785],{"className":167,"code":784,"language":169,"meta":170,"style":170},"const { pipeline } = require(\"stream\");\nconst { promisify } = require(\"util\");\nconst pipelineAsync = promisify(pipeline);\n\n\u002F\u002F 或者使用 stream\u002Fpromises 直接导入 Promise 版本\nconst { pipeline: pipelinePromise } = require(\"stream\u002Fpromises\");\n\nasync function run() {\n    await pipelinePromise(\n        fs.createReadStream(\"input.txt\"),\n        zlib.createGzip(),\n        fs.createWriteStream(\"input.gz\")\n    );\n    console.log(\"压缩完成\");\n}\n",[37,786,787,814,842,858,862,867,901,905,920,931,954,968,988,995,1017],{"__ignoreMap":170},[174,788,789,791,793,796,798,800,802,804,806,808,810,812],{"class":176,"line":177},[174,790,181],{"class":180},[174,792,185],{"class":184},[174,794,795],{"class":188}," pipeline",[174,797,208],{"class":184},[174,799,212],{"class":211},[174,801,216],{"class":215},[174,803,220],{"class":219},[174,805,224],{"class":223},[174,807,13],{"class":227},[174,809,224],{"class":223},[174,811,232],{"class":219},[174,813,235],{"class":184},[174,815,816,818,820,823,825,827,829,831,833,836,838,840],{"class":176,"line":238},[174,817,181],{"class":180},[174,819,185],{"class":184},[174,821,822],{"class":188}," promisify",[174,824,208],{"class":184},[174,826,212],{"class":211},[174,828,216],{"class":215},[174,830,220],{"class":219},[174,832,224],{"class":223},[174,834,835],{"class":227},"util",[174,837,224],{"class":223},[174,839,232],{"class":219},[174,841,235],{"class":184},[174,843,844,846,849,851,853,856],{"class":176,"line":245},[174,845,181],{"class":180},[174,847,848],{"class":188}," pipelineAsync",[174,850,212],{"class":211},[174,852,822],{"class":215},[174,854,855],{"class":219},"(pipeline)",[174,857,235],{"class":184},[174,859,860],{"class":176,"line":252},[174,861,242],{"emptyLinePlaceholder":241},[174,863,864],{"class":176,"line":295},[174,865,866],{"class":248},"\u002F\u002F 或者使用 stream\u002Fpromises 直接导入 Promise 版本\n",[174,868,869,871,873,876,879,882,884,886,888,890,892,895,897,899],{"class":176,"line":300},[174,870,181],{"class":180},[174,872,185],{"class":184},[174,874,795],{"class":875},"sucvu",[174,877,878],{"class":184},":",[174,880,881],{"class":188}," pipelinePromise",[174,883,208],{"class":184},[174,885,212],{"class":211},[174,887,216],{"class":215},[174,889,220],{"class":219},[174,891,224],{"class":223},[174,893,894],{"class":227},"stream\u002Fpromises",[174,896,224],{"class":223},[174,898,232],{"class":219},[174,900,235],{"class":184},[174,902,903],{"class":176,"line":306},[174,904,242],{"emptyLinePlaceholder":241},[174,906,907,910,913,916,918],{"class":176,"line":337},[174,908,909],{"class":180},"async",[174,911,912],{"class":180}," function",[174,914,915],{"class":215}," run",[174,917,515],{"class":184},[174,919,383],{"class":184},[174,921,922,926,928],{"class":176,"line":342},[174,923,925],{"class":924},"sVHd0","    await",[174,927,881],{"class":215},[174,929,930],{"class":514},"(\n",[174,932,933,936,938,940,942,944,947,949,951],{"class":176,"line":348},[174,934,935],{"class":219},"        fs",[174,937,264],{"class":184},[174,939,662],{"class":215},[174,941,220],{"class":514},[174,943,224],{"class":223},[174,945,946],{"class":227},"input.txt",[174,948,224],{"class":223},[174,950,232],{"class":514},[174,952,953],{"class":184},",\n",[174,955,956,959,961,964,966],{"class":176,"line":368},[174,957,958],{"class":219},"        zlib",[174,960,264],{"class":184},[174,962,963],{"class":215},"createGzip",[174,965,515],{"class":514},[174,967,953],{"class":184},[174,969,970,972,974,976,978,980,983,985],{"class":176,"line":386},[174,971,935],{"class":219},[174,973,264],{"class":184},[174,975,321],{"class":215},[174,977,220],{"class":514},[174,979,224],{"class":223},[174,981,982],{"class":227},"input.gz",[174,984,224],{"class":223},[174,986,987],{"class":514},")\n",[174,989,990,993],{"class":176,"line":392},[174,991,992],{"class":514},"    )",[174,994,235],{"class":184},[174,996,997,1000,1002,1004,1006,1008,1011,1013,1015],{"class":176,"line":398},[174,998,999],{"class":219},"    console",[174,1001,264],{"class":184},[174,1003,752],{"class":215},[174,1005,220],{"class":514},[174,1007,224],{"class":223},[174,1009,1010],{"class":227},"压缩完成",[174,1012,224],{"class":223},[174,1014,232],{"class":514},[174,1016,235],{"class":184},[174,1018,1019],{"class":176,"line":423},[174,1020,1021],{"class":184},"}\n",[41,1023,1025],{"id":1024},"三自定义流实现","三、自定义流实现",[28,1027,1028],{},"通过继承核心流类并实现必要的方法，可以创建定制流。",[161,1030,1032],{"id":1031},"_1-自定义可读流","1. 自定义可读流",[28,1034,1035,1036,1039,1040,621,1043,1046],{},"需要实现 ",[37,1037,1038],{},"_read(size)"," 方法，内部调用 ",[37,1041,1042],{},"push(chunk)",[37,1044,1045],{},"push(null)"," 结束。",[165,1048,1050],{"className":167,"code":1049,"language":169,"meta":170,"style":170},"const { Readable } = require(\"stream\");\n\nclass Counter extends Readable {\n    constructor(options) {\n        super(options);\n        this.max = 10;\n        this.index = 0;\n    }\n    _read(size) {\n        if (this.index \u003C this.max) {\n            this.push(String(this.index++));\n        } else {\n            this.push(null); \u002F\u002F 结束\n        }\n    }\n}\n\nconst counter = new Counter();\ncounter.pipe(process.stdout); \u002F\u002F 输出 0 1 2 ... 9\n",[37,1051,1052,1078,1082,1098,1112,1125,1143,1159,1164,1177,1207,1237,1247,1267,1272,1276,1280,1284,1301],{"__ignoreMap":170},[174,1053,1054,1056,1058,1060,1062,1064,1066,1068,1070,1072,1074,1076],{"class":176,"line":177},[174,1055,181],{"class":180},[174,1057,185],{"class":184},[174,1059,189],{"class":188},[174,1061,208],{"class":184},[174,1063,212],{"class":211},[174,1065,216],{"class":215},[174,1067,220],{"class":219},[174,1069,224],{"class":223},[174,1071,13],{"class":227},[174,1073,224],{"class":223},[174,1075,232],{"class":219},[174,1077,235],{"class":184},[174,1079,1080],{"class":176,"line":238},[174,1081,242],{"emptyLinePlaceholder":241},[174,1083,1084,1087,1091,1094,1096],{"class":176,"line":245},[174,1085,1086],{"class":180},"class",[174,1088,1090],{"class":1089},"sbgvK"," Counter",[174,1092,1093],{"class":180}," extends",[174,1095,189],{"class":1089},[174,1097,383],{"class":184},[174,1099,1100,1103,1105,1108,1110],{"class":176,"line":252},[174,1101,1102],{"class":180},"    constructor",[174,1104,220],{"class":184},[174,1106,1107],{"class":377},"options",[174,1109,232],{"class":184},[174,1111,383],{"class":184},[174,1113,1114,1117,1119,1121,1123],{"class":176,"line":295},[174,1115,1116],{"class":188},"        super",[174,1118,220],{"class":514},[174,1120,1107],{"class":219},[174,1122,232],{"class":514},[174,1124,235],{"class":184},[174,1126,1127,1130,1132,1135,1137,1141],{"class":176,"line":300},[174,1128,1129],{"class":535},"        this",[174,1131,264],{"class":184},[174,1133,1134],{"class":219},"max",[174,1136,212],{"class":211},[174,1138,1140],{"class":1139},"srdBf"," 10",[174,1142,235],{"class":184},[174,1144,1145,1147,1149,1152,1154,1157],{"class":176,"line":306},[174,1146,1129],{"class":535},[174,1148,264],{"class":184},[174,1150,1151],{"class":219},"index",[174,1153,212],{"class":211},[174,1155,1156],{"class":1139}," 0",[174,1158,235],{"class":184},[174,1160,1161],{"class":176,"line":337},[174,1162,1163],{"class":184},"    }\n",[174,1165,1166,1169,1171,1173,1175],{"class":176,"line":342},[174,1167,1168],{"class":371},"    _read",[174,1170,220],{"class":184},[174,1172,378],{"class":377},[174,1174,232],{"class":184},[174,1176,383],{"class":184},[174,1178,1179,1182,1185,1188,1190,1192,1195,1198,1200,1202,1205],{"class":176,"line":348},[174,1180,1181],{"class":924},"        if",[174,1183,1184],{"class":514}," (",[174,1186,1187],{"class":535},"this",[174,1189,264],{"class":184},[174,1191,1151],{"class":219},[174,1193,1194],{"class":211}," \u003C",[174,1196,1197],{"class":535}," this",[174,1199,264],{"class":184},[174,1201,1134],{"class":219},[174,1203,1204],{"class":514},") ",[174,1206,365],{"class":184},[174,1208,1209,1212,1214,1217,1219,1222,1224,1226,1228,1230,1233,1235],{"class":176,"line":368},[174,1210,1211],{"class":535},"            this",[174,1213,264],{"class":184},[174,1215,1216],{"class":215},"push",[174,1218,220],{"class":514},[174,1220,1221],{"class":215},"String",[174,1223,220],{"class":514},[174,1225,1187],{"class":535},[174,1227,264],{"class":184},[174,1229,1151],{"class":219},[174,1231,1232],{"class":211},"++",[174,1234,764],{"class":514},[174,1236,235],{"class":184},[174,1238,1239,1242,1245],{"class":176,"line":386},[174,1240,1241],{"class":184},"        }",[174,1243,1244],{"class":924}," else",[174,1246,383],{"class":184},[174,1248,1249,1251,1253,1255,1257,1259,1261,1264],{"class":176,"line":392},[174,1250,1211],{"class":535},[174,1252,264],{"class":184},[174,1254,1216],{"class":215},[174,1256,220],{"class":514},[174,1258,536],{"class":535},[174,1260,232],{"class":514},[174,1262,1263],{"class":184},";",[174,1265,1266],{"class":248}," \u002F\u002F 结束\n",[174,1268,1269],{"class":176,"line":398},[174,1270,1271],{"class":184},"        }\n",[174,1273,1274],{"class":176,"line":423},[174,1275,1163],{"class":184},[174,1277,1278],{"class":176,"line":429},[174,1279,1021],{"class":184},[174,1281,1282],{"class":176,"line":434},[174,1283,242],{"emptyLinePlaceholder":241},[174,1285,1286,1288,1291,1293,1295,1297,1299],{"class":176,"line":444},[174,1287,181],{"class":180},[174,1289,1290],{"class":188}," counter",[174,1292,212],{"class":211},[174,1294,358],{"class":211},[174,1296,1090],{"class":215},[174,1298,515],{"class":219},[174,1300,235],{"class":184},[174,1302,1303,1306,1308,1310,1313,1315,1318,1320],{"class":176,"line":449},[174,1304,1305],{"class":219},"counter",[174,1307,264],{"class":184},[174,1309,565],{"class":215},[174,1311,1312],{"class":219},"(process",[174,1314,264],{"class":184},[174,1316,1317],{"class":219},"stdout)",[174,1319,1263],{"class":184},[174,1321,1322],{"class":248}," \u002F\u002F 输出 0 1 2 ... 9\n",[161,1324,1326],{"id":1325},"_2-自定义可写流","2. 自定义可写流",[28,1328,1035,1329,1332,1333,627],{},[37,1330,1331],{},"_write(chunk, encoding, callback)","，处理数据后调用 ",[37,1334,1335],{},"callback()",[165,1337,1339],{"className":167,"code":1338,"language":169,"meta":170,"style":170},"const { Writable } = require(\"stream\");\n\nclass MyWritable extends Writable {\n    _write(chunk, encoding, callback) {\n        console.log(`写入: ${chunk.toString()}`);\n        callback(); \u002F\u002F 继续接收下一个块\n    }\n}\n\nconst writable = new MyWritable();\nwritable.write(\"Hello\\n\");\nwritable.write(\"World\");\nwritable.end();\n",[37,1340,1341,1367,1371,1384,1405,1441,1452,1456,1460,1464,1480,1505,1525],{"__ignoreMap":170},[174,1342,1343,1345,1347,1349,1351,1353,1355,1357,1359,1361,1363,1365],{"class":176,"line":177},[174,1344,181],{"class":180},[174,1346,185],{"class":184},[174,1348,195],{"class":188},[174,1350,208],{"class":184},[174,1352,212],{"class":211},[174,1354,216],{"class":215},[174,1356,220],{"class":219},[174,1358,224],{"class":223},[174,1360,13],{"class":227},[174,1362,224],{"class":223},[174,1364,232],{"class":219},[174,1366,235],{"class":184},[174,1368,1369],{"class":176,"line":238},[174,1370,242],{"emptyLinePlaceholder":241},[174,1372,1373,1375,1378,1380,1382],{"class":176,"line":245},[174,1374,1086],{"class":180},[174,1376,1377],{"class":1089}," MyWritable",[174,1379,1093],{"class":180},[174,1381,195],{"class":1089},[174,1383,383],{"class":184},[174,1385,1386,1389,1391,1393,1395,1397,1399,1401,1403],{"class":176,"line":252},[174,1387,1388],{"class":371},"    _write",[174,1390,220],{"class":184},[174,1392,406],{"class":377},[174,1394,192],{"class":184},[174,1396,411],{"class":377},[174,1398,192],{"class":184},[174,1400,416],{"class":377},[174,1402,232],{"class":184},[174,1404,383],{"class":184},[174,1406,1407,1410,1412,1414,1416,1419,1422,1425,1427,1429,1431,1434,1437,1439],{"class":176,"line":295},[174,1408,1409],{"class":219},"        console",[174,1411,264],{"class":184},[174,1413,752],{"class":215},[174,1415,220],{"class":514},[174,1417,1418],{"class":223},"`",[174,1420,1421],{"class":227},"写入: ",[174,1423,1424],{"class":223},"${",[174,1426,406],{"class":219},[174,1428,264],{"class":223},[174,1430,511],{"class":215},[174,1432,515],{"class":1433},"sfo-9",[174,1435,1436],{"class":223},"}`",[174,1438,232],{"class":514},[174,1440,235],{"class":184},[174,1442,1443,1445,1447,1449],{"class":176,"line":300},[174,1444,530],{"class":215},[174,1446,515],{"class":514},[174,1448,1263],{"class":184},[174,1450,1451],{"class":248}," \u002F\u002F 继续接收下一个块\n",[174,1453,1454],{"class":176,"line":306},[174,1455,1163],{"class":184},[174,1457,1458],{"class":176,"line":337},[174,1459,1021],{"class":184},[174,1461,1462],{"class":176,"line":342},[174,1463,242],{"emptyLinePlaceholder":241},[174,1465,1466,1468,1470,1472,1474,1476,1478],{"class":176,"line":348},[174,1467,181],{"class":180},[174,1469,311],{"class":188},[174,1471,212],{"class":211},[174,1473,358],{"class":211},[174,1475,1377],{"class":215},[174,1477,515],{"class":219},[174,1479,235],{"class":184},[174,1481,1482,1485,1487,1490,1492,1494,1496,1499,1501,1503],{"class":176,"line":368},[174,1483,1484],{"class":219},"writable",[174,1486,264],{"class":184},[174,1488,1489],{"class":215},"write",[174,1491,220],{"class":219},[174,1493,224],{"class":223},[174,1495,275],{"class":227},[174,1497,1498],{"class":188},"\\n",[174,1500,224],{"class":223},[174,1502,232],{"class":219},[174,1504,235],{"class":184},[174,1506,1507,1509,1511,1513,1515,1517,1519,1521,1523],{"class":176,"line":386},[174,1508,1484],{"class":219},[174,1510,264],{"class":184},[174,1512,1489],{"class":215},[174,1514,220],{"class":219},[174,1516,224],{"class":223},[174,1518,285],{"class":227},[174,1520,224],{"class":223},[174,1522,232],{"class":219},[174,1524,235],{"class":184},[174,1526,1527,1529,1531,1534,1536],{"class":176,"line":392},[174,1528,1484],{"class":219},[174,1530,264],{"class":184},[174,1532,1533],{"class":215},"end",[174,1535,515],{"class":219},[174,1537,235],{"class":184},[161,1539,1541],{"id":1540},"_3-自定义转换流","3. 自定义转换流",[28,1543,1544,1545,1548,1549,627],{},"实现 ",[37,1546,1547],{},"_transform(chunk, encoding, callback)","，处理后调用 ",[37,1550,1551],{},"callback(null, transformedChunk)",[165,1553,1555],{"className":167,"code":1554,"language":169,"meta":170,"style":170},"const { Transform } = require(\"stream\");\n\nclass UpperCaseTransform extends Transform {\n    _transform(chunk, encoding, callback) {\n        const upper = chunk.toString().toUpperCase();\n        callback(null, upper);\n    }\n}\n\nconst transform = new UpperCaseTransform();\nprocess.stdin.pipe(transform).pipe(process.stdout);\n",[37,1556,1557,1583,1587,1600,1621,1646,1662,1666,1670,1674,1690],{"__ignoreMap":170},[174,1558,1559,1561,1563,1565,1567,1569,1571,1573,1575,1577,1579,1581],{"class":176,"line":177},[174,1560,181],{"class":180},[174,1562,185],{"class":184},[174,1564,205],{"class":188},[174,1566,208],{"class":184},[174,1568,212],{"class":211},[174,1570,216],{"class":215},[174,1572,220],{"class":219},[174,1574,224],{"class":223},[174,1576,13],{"class":227},[174,1578,224],{"class":223},[174,1580,232],{"class":219},[174,1582,235],{"class":184},[174,1584,1585],{"class":176,"line":238},[174,1586,242],{"emptyLinePlaceholder":241},[174,1588,1589,1591,1594,1596,1598],{"class":176,"line":245},[174,1590,1086],{"class":180},[174,1592,1593],{"class":1089}," UpperCaseTransform",[174,1595,1093],{"class":180},[174,1597,205],{"class":1089},[174,1599,383],{"class":184},[174,1601,1602,1605,1607,1609,1611,1613,1615,1617,1619],{"class":176,"line":252},[174,1603,1604],{"class":371},"    _transform",[174,1606,220],{"class":184},[174,1608,406],{"class":377},[174,1610,192],{"class":184},[174,1612,411],{"class":377},[174,1614,192],{"class":184},[174,1616,416],{"class":377},[174,1618,232],{"class":184},[174,1620,383],{"class":184},[174,1622,1623,1625,1628,1630,1632,1634,1636,1638,1640,1642,1644],{"class":176,"line":295},[174,1624,498],{"class":180},[174,1626,1627],{"class":188}," upper",[174,1629,212],{"class":211},[174,1631,506],{"class":219},[174,1633,264],{"class":184},[174,1635,511],{"class":215},[174,1637,515],{"class":514},[174,1639,264],{"class":184},[174,1641,520],{"class":215},[174,1643,515],{"class":514},[174,1645,235],{"class":184},[174,1647,1648,1650,1652,1654,1656,1658,1660],{"class":176,"line":300},[174,1649,530],{"class":215},[174,1651,220],{"class":514},[174,1653,536],{"class":535},[174,1655,192],{"class":184},[174,1657,1627],{"class":219},[174,1659,232],{"class":514},[174,1661,235],{"class":184},[174,1663,1664],{"class":176,"line":306},[174,1665,1163],{"class":184},[174,1667,1668],{"class":176,"line":337},[174,1669,1021],{"class":184},[174,1671,1672],{"class":176,"line":342},[174,1673,242],{"emptyLinePlaceholder":241},[174,1675,1676,1678,1680,1682,1684,1686,1688],{"class":176,"line":348},[174,1677,181],{"class":180},[174,1679,460],{"class":188},[174,1681,212],{"class":211},[174,1683,358],{"class":211},[174,1685,1593],{"class":215},[174,1687,515],{"class":219},[174,1689,235],{"class":184},[174,1691,1692,1695,1697,1700,1702,1704,1707,1709,1711,1713,1715,1717],{"class":176,"line":368},[174,1693,1694],{"class":219},"process",[174,1696,264],{"class":184},[174,1698,1699],{"class":219},"stdin",[174,1701,264],{"class":184},[174,1703,565],{"class":215},[174,1705,1706],{"class":219},"(transform)",[174,1708,264],{"class":184},[174,1710,565],{"class":215},[174,1712,1312],{"class":219},[174,1714,264],{"class":184},[174,1716,1317],{"class":219},[174,1718,235],{"class":184},[161,1720,1722],{"id":1721},"_4-自定义双工流","4. 自定义双工流",[28,1724,1725,1726,1729,1730,1733,1734,627],{},"需同时实现 ",[37,1727,1728],{},"_read"," 和 ",[37,1731,1732],{},"_write","，且两者独立。如果不涉及数据转换，直接使用 ",[37,1735,1736],{},"Duplex",[41,1738,1740,1741,1743,1744,1729,1746],{"id":1739},"四实用工具streampromises-中的-pipeline-和-finished","四、实用工具：",[37,1742,894],{}," 中的 ",[37,1745,569],{},[37,1747,1748],{},"finished",[161,1750,1752,1753,1755],{"id":1751},"_1-pipelinepromise-版本","1. ",[37,1754,569],{},"（Promise 版本）",[28,1757,1758],{},"用于串联多个流，返回 Promise，并在任何流发生错误时中止并清理。",[165,1760,1762],{"className":167,"code":1761,"language":169,"meta":170,"style":170},"const { pipeline } = require(\"stream\u002Fpromises\");\nconst fs = require(\"fs\");\nconst zlib = require(\"zlib\");\n\nasync function compress() {\n    await pipeline(\n        fs.createReadStream(\"file.txt\"),\n        zlib.createGzip(),\n        fs.createWriteStream(\"file.gz\")\n    );\n    console.log(\"压缩成功\");\n}\n",[37,1763,1764,1790,1813,1837,1841,1854,1862,1883,1895,1914,1920,1941],{"__ignoreMap":170},[174,1765,1766,1768,1770,1772,1774,1776,1778,1780,1782,1784,1786,1788],{"class":176,"line":177},[174,1767,181],{"class":180},[174,1769,185],{"class":184},[174,1771,795],{"class":188},[174,1773,208],{"class":184},[174,1775,212],{"class":211},[174,1777,216],{"class":215},[174,1779,220],{"class":219},[174,1781,224],{"class":223},[174,1783,894],{"class":227},[174,1785,224],{"class":223},[174,1787,232],{"class":219},[174,1789,235],{"class":184},[174,1791,1792,1794,1796,1798,1800,1802,1804,1807,1809,1811],{"class":176,"line":238},[174,1793,181],{"class":180},[174,1795,316],{"class":188},[174,1797,212],{"class":211},[174,1799,216],{"class":215},[174,1801,220],{"class":219},[174,1803,224],{"class":223},[174,1805,1806],{"class":227},"fs",[174,1808,224],{"class":223},[174,1810,232],{"class":219},[174,1812,235],{"class":184},[174,1814,1815,1817,1820,1822,1824,1826,1828,1831,1833,1835],{"class":176,"line":245},[174,1816,181],{"class":180},[174,1818,1819],{"class":188}," zlib",[174,1821,212],{"class":211},[174,1823,216],{"class":215},[174,1825,220],{"class":219},[174,1827,224],{"class":223},[174,1829,1830],{"class":227},"zlib",[174,1832,224],{"class":223},[174,1834,232],{"class":219},[174,1836,235],{"class":184},[174,1838,1839],{"class":176,"line":252},[174,1840,242],{"emptyLinePlaceholder":241},[174,1842,1843,1845,1847,1850,1852],{"class":176,"line":295},[174,1844,909],{"class":180},[174,1846,912],{"class":180},[174,1848,1849],{"class":215}," compress",[174,1851,515],{"class":184},[174,1853,383],{"class":184},[174,1855,1856,1858,1860],{"class":176,"line":300},[174,1857,925],{"class":924},[174,1859,795],{"class":215},[174,1861,930],{"class":514},[174,1863,1864,1866,1868,1870,1872,1874,1877,1879,1881],{"class":176,"line":306},[174,1865,935],{"class":219},[174,1867,264],{"class":184},[174,1869,662],{"class":215},[174,1871,220],{"class":514},[174,1873,224],{"class":223},[174,1875,1876],{"class":227},"file.txt",[174,1878,224],{"class":223},[174,1880,232],{"class":514},[174,1882,953],{"class":184},[174,1884,1885,1887,1889,1891,1893],{"class":176,"line":337},[174,1886,958],{"class":219},[174,1888,264],{"class":184},[174,1890,963],{"class":215},[174,1892,515],{"class":514},[174,1894,953],{"class":184},[174,1896,1897,1899,1901,1903,1905,1907,1910,1912],{"class":176,"line":342},[174,1898,935],{"class":219},[174,1900,264],{"class":184},[174,1902,321],{"class":215},[174,1904,220],{"class":514},[174,1906,224],{"class":223},[174,1908,1909],{"class":227},"file.gz",[174,1911,224],{"class":223},[174,1913,987],{"class":514},[174,1915,1916,1918],{"class":176,"line":348},[174,1917,992],{"class":514},[174,1919,235],{"class":184},[174,1921,1922,1924,1926,1928,1930,1932,1935,1937,1939],{"class":176,"line":368},[174,1923,999],{"class":219},[174,1925,264],{"class":184},[174,1927,752],{"class":215},[174,1929,220],{"class":514},[174,1931,224],{"class":223},[174,1933,1934],{"class":227},"压缩成功",[174,1936,224],{"class":223},[174,1938,232],{"class":514},[174,1940,235],{"class":184},[174,1942,1943],{"class":176,"line":386},[174,1944,1021],{"class":184},[161,1946,631,1948],{"id":1947},"_2-finished",[37,1949,1748],{},[28,1951,1952],{},"检测流是否完成（或出错），返回 Promise。常用于手动管理流结束。",[165,1954,1956],{"className":167,"code":1955,"language":169,"meta":170,"style":170},"const { finished } = require(\"stream\u002Fpromises\");\n\nasync function monitor(stream) {\n    try {\n        await finished(stream);\n        console.log(\"流已完成\");\n    } catch (err) {\n        console.error(\"流错误:\", err);\n    }\n}\n\nconst rs = fs.createReadStream(\"somefile.txt\");\nmonitor(rs);\n",[37,1957,1958,1985,1989,2006,2013,2028,2049,2066,2092,2096,2100,2104,2132],{"__ignoreMap":170},[174,1959,1960,1962,1964,1967,1969,1971,1973,1975,1977,1979,1981,1983],{"class":176,"line":177},[174,1961,181],{"class":180},[174,1963,185],{"class":184},[174,1965,1966],{"class":188}," finished",[174,1968,208],{"class":184},[174,1970,212],{"class":211},[174,1972,216],{"class":215},[174,1974,220],{"class":219},[174,1976,224],{"class":223},[174,1978,894],{"class":227},[174,1980,224],{"class":223},[174,1982,232],{"class":219},[174,1984,235],{"class":184},[174,1986,1987],{"class":176,"line":238},[174,1988,242],{"emptyLinePlaceholder":241},[174,1990,1991,1993,1995,1998,2000,2002,2004],{"class":176,"line":245},[174,1992,909],{"class":180},[174,1994,912],{"class":180},[174,1996,1997],{"class":215}," monitor",[174,1999,220],{"class":184},[174,2001,13],{"class":377},[174,2003,232],{"class":184},[174,2005,383],{"class":184},[174,2007,2008,2011],{"class":176,"line":252},[174,2009,2010],{"class":924},"    try",[174,2012,383],{"class":184},[174,2014,2015,2018,2020,2022,2024,2026],{"class":176,"line":295},[174,2016,2017],{"class":924},"        await",[174,2019,1966],{"class":215},[174,2021,220],{"class":514},[174,2023,13],{"class":219},[174,2025,232],{"class":514},[174,2027,235],{"class":184},[174,2029,2030,2032,2034,2036,2038,2040,2043,2045,2047],{"class":176,"line":300},[174,2031,1409],{"class":219},[174,2033,264],{"class":184},[174,2035,752],{"class":215},[174,2037,220],{"class":514},[174,2039,224],{"class":223},[174,2041,2042],{"class":227},"流已完成",[174,2044,224],{"class":223},[174,2046,232],{"class":514},[174,2048,235],{"class":184},[174,2050,2051,2054,2057,2059,2062,2064],{"class":176,"line":306},[174,2052,2053],{"class":184},"    }",[174,2055,2056],{"class":924}," catch",[174,2058,1184],{"class":514},[174,2060,2061],{"class":219},"err",[174,2063,1204],{"class":514},[174,2065,365],{"class":184},[174,2067,2068,2070,2072,2074,2076,2078,2081,2083,2085,2088,2090],{"class":176,"line":337},[174,2069,1409],{"class":219},[174,2071,264],{"class":184},[174,2073,640],{"class":215},[174,2075,220],{"class":514},[174,2077,224],{"class":223},[174,2079,2080],{"class":227},"流错误:",[174,2082,224],{"class":223},[174,2084,192],{"class":184},[174,2086,2087],{"class":219}," err",[174,2089,232],{"class":514},[174,2091,235],{"class":184},[174,2093,2094],{"class":176,"line":342},[174,2095,1163],{"class":184},[174,2097,2098],{"class":176,"line":348},[174,2099,1021],{"class":184},[174,2101,2102],{"class":176,"line":368},[174,2103,242],{"emptyLinePlaceholder":241},[174,2105,2106,2108,2111,2113,2115,2117,2119,2121,2123,2126,2128,2130],{"class":176,"line":386},[174,2107,181],{"class":180},[174,2109,2110],{"class":188}," rs",[174,2112,212],{"class":211},[174,2114,316],{"class":219},[174,2116,264],{"class":184},[174,2118,662],{"class":215},[174,2120,220],{"class":219},[174,2122,224],{"class":223},[174,2124,2125],{"class":227},"somefile.txt",[174,2127,224],{"class":223},[174,2129,232],{"class":219},[174,2131,235],{"class":184},[174,2133,2134,2137,2140],{"class":176,"line":392},[174,2135,2136],{"class":215},"monitor",[174,2138,2139],{"class":219},"(rs)",[174,2141,235],{"class":184},[28,2143,2144,2146,2147,2149],{},[37,2145,1748],{}," 也可用于每个独立流，而 ",[37,2148,569],{}," 更适合多流串联。",[2151,2152,2153],"blockquote",{},[28,2154,2155,2158,2159,2161,2162,627],{},[32,2156,2157],{},"注意","：",[37,2160,894],{}," 从 Node.js 15 开始稳定可用，对于较低版本可使用 ",[37,2163,2164],{},"util.promisify(require('stream').finished)",[41,2166,2168],{"id":2167},"五背压手动处理示例","五、背压手动处理示例",[28,2170,2171,2172,621,2174,2176],{},"当不使用 ",[37,2173,565],{},[37,2175,569],{}," 时，需要手动处理背压：",[165,2178,2180],{"className":167,"code":2179,"language":169,"meta":170,"style":170},"const rs = fs.createReadStream(\"large.txt\");\nconst ws = fs.createWriteStream(\"copy.txt\");\n\nrs.on(\"data\", chunk => {\n    const canWrite = ws.write(chunk);\n    if (!canWrite) {\n        rs.pause(); \u002F\u002F 暂停读取\n        ws.once(\"drain\", () => rs.resume()); \u002F\u002F 等待可写流排空\n    }\n});\nrs.on(\"end\", () => ws.end());\nws.on(\"finish\", () => console.log(\"复制结束\"));\n",[37,2181,2182,2209,2236,2240,2266,2290,2307,2324,2363,2367,2375,2407],{"__ignoreMap":170},[174,2183,2184,2186,2188,2190,2192,2194,2196,2198,2200,2203,2205,2207],{"class":176,"line":177},[174,2185,181],{"class":180},[174,2187,2110],{"class":188},[174,2189,212],{"class":211},[174,2191,316],{"class":219},[174,2193,264],{"class":184},[174,2195,662],{"class":215},[174,2197,220],{"class":219},[174,2199,224],{"class":223},[174,2201,2202],{"class":227},"large.txt",[174,2204,224],{"class":223},[174,2206,232],{"class":219},[174,2208,235],{"class":184},[174,2210,2211,2213,2216,2218,2220,2222,2224,2226,2228,2230,2232,2234],{"class":176,"line":238},[174,2212,181],{"class":180},[174,2214,2215],{"class":188}," ws",[174,2217,212],{"class":211},[174,2219,316],{"class":219},[174,2221,264],{"class":184},[174,2223,321],{"class":215},[174,2225,220],{"class":219},[174,2227,224],{"class":223},[174,2229,697],{"class":227},[174,2231,224],{"class":223},[174,2233,232],{"class":219},[174,2235,235],{"class":184},[174,2237,2238],{"class":176,"line":245},[174,2239,242],{"emptyLinePlaceholder":241},[174,2241,2242,2245,2247,2249,2251,2253,2256,2258,2260,2262,2264],{"class":176,"line":252},[174,2243,2244],{"class":219},"rs",[174,2246,264],{"class":184},[174,2248,727],{"class":215},[174,2250,220],{"class":219},[174,2252,224],{"class":223},[174,2254,2255],{"class":227},"data",[174,2257,224],{"class":223},[174,2259,192],{"class":184},[174,2261,506],{"class":377},[174,2263,744],{"class":180},[174,2265,383],{"class":184},[174,2267,2268,2271,2274,2276,2278,2280,2282,2284,2286,2288],{"class":176,"line":295},[174,2269,2270],{"class":180},"    const",[174,2272,2273],{"class":188}," canWrite",[174,2275,212],{"class":211},[174,2277,2215],{"class":219},[174,2279,264],{"class":184},[174,2281,1489],{"class":215},[174,2283,220],{"class":514},[174,2285,406],{"class":219},[174,2287,232],{"class":514},[174,2289,235],{"class":184},[174,2291,2292,2295,2297,2300,2303,2305],{"class":176,"line":300},[174,2293,2294],{"class":924},"    if",[174,2296,1184],{"class":514},[174,2298,2299],{"class":211},"!",[174,2301,2302],{"class":219},"canWrite",[174,2304,1204],{"class":514},[174,2306,365],{"class":184},[174,2308,2309,2312,2314,2317,2319,2321],{"class":176,"line":306},[174,2310,2311],{"class":219},"        rs",[174,2313,264],{"class":184},[174,2315,2316],{"class":215},"pause",[174,2318,515],{"class":514},[174,2320,1263],{"class":184},[174,2322,2323],{"class":248}," \u002F\u002F 暂停读取\n",[174,2325,2326,2329,2331,2334,2336,2338,2340,2342,2344,2346,2348,2350,2352,2355,2358,2360],{"class":176,"line":337},[174,2327,2328],{"class":219},"        ws",[174,2330,264],{"class":184},[174,2332,2333],{"class":215},"once",[174,2335,220],{"class":514},[174,2337,224],{"class":223},[174,2339,614],{"class":227},[174,2341,224],{"class":223},[174,2343,192],{"class":184},[174,2345,741],{"class":184},[174,2347,744],{"class":180},[174,2349,2110],{"class":219},[174,2351,264],{"class":184},[174,2353,2354],{"class":215},"resume",[174,2356,2357],{"class":514},"())",[174,2359,1263],{"class":184},[174,2361,2362],{"class":248}," \u002F\u002F 等待可写流排空\n",[174,2364,2365],{"class":176,"line":342},[174,2366,1163],{"class":184},[174,2368,2369,2371,2373],{"class":176,"line":348},[174,2370,437],{"class":184},[174,2372,232],{"class":219},[174,2374,235],{"class":184},[174,2376,2377,2379,2381,2383,2385,2387,2389,2391,2393,2395,2397,2399,2401,2403,2405],{"class":176,"line":368},[174,2378,2244],{"class":219},[174,2380,264],{"class":184},[174,2382,727],{"class":215},[174,2384,220],{"class":219},[174,2386,224],{"class":223},[174,2388,1533],{"class":227},[174,2390,224],{"class":223},[174,2392,192],{"class":184},[174,2394,741],{"class":184},[174,2396,744],{"class":180},[174,2398,2215],{"class":219},[174,2400,264],{"class":184},[174,2402,1533],{"class":215},[174,2404,2357],{"class":219},[174,2406,235],{"class":184},[174,2408,2409,2412,2414,2416,2418,2420,2422,2424,2426,2428,2430,2432,2434,2436,2438,2440,2443,2445,2447],{"class":176,"line":386},[174,2410,2411],{"class":219},"ws",[174,2413,264],{"class":184},[174,2415,727],{"class":215},[174,2417,220],{"class":219},[174,2419,224],{"class":223},[174,2421,734],{"class":227},[174,2423,224],{"class":223},[174,2425,192],{"class":184},[174,2427,741],{"class":184},[174,2429,744],{"class":180},[174,2431,747],{"class":219},[174,2433,264],{"class":184},[174,2435,752],{"class":215},[174,2437,220],{"class":219},[174,2439,224],{"class":223},[174,2441,2442],{"class":227},"复制结束",[174,2444,224],{"class":223},[174,2446,764],{"class":219},[174,2448,235],{"class":184},[28,2450,2451,2453],{},[37,2452,565],{}," 内部就是实现这样的逻辑。",[41,2455,2457],{"id":2456},"六对象模式object-mode","六、对象模式（Object Mode）",[28,2459,2460,2461,2464,2465,2468],{},"默认流传输的是 ",[37,2462,2463],{},"Buffer"," 或字符串，通过设置 ",[37,2466,2467],{},"objectMode: true"," 可以传输任意 JavaScript 对象（如 JSON 数据），但会禁用背压控制，需谨慎使用。",[165,2470,2472],{"className":167,"code":2471,"language":169,"meta":170,"style":170},"const { Readable } = require(\"stream\");\nconst objStream = new Readable({\n    objectMode: true,\n    read() {\n        this.push({ id: 1 });\n        this.push({ id: 2 });\n        this.push(null);\n    },\n});\nobjStream.on(\"data\", obj => console.log(obj));\n",[37,2473,2474,2500,2517,2530,2538,2565,2590,2606,2610,2618],{"__ignoreMap":170},[174,2475,2476,2478,2480,2482,2484,2486,2488,2490,2492,2494,2496,2498],{"class":176,"line":177},[174,2477,181],{"class":180},[174,2479,185],{"class":184},[174,2481,189],{"class":188},[174,2483,208],{"class":184},[174,2485,212],{"class":211},[174,2487,216],{"class":215},[174,2489,220],{"class":219},[174,2491,224],{"class":223},[174,2493,13],{"class":227},[174,2495,224],{"class":223},[174,2497,232],{"class":219},[174,2499,235],{"class":184},[174,2501,2502,2504,2507,2509,2511,2513,2515],{"class":176,"line":238},[174,2503,181],{"class":180},[174,2505,2506],{"class":188}," objStream",[174,2508,212],{"class":211},[174,2510,358],{"class":211},[174,2512,189],{"class":215},[174,2514,220],{"class":219},[174,2516,365],{"class":184},[174,2518,2519,2522,2524,2528],{"class":176,"line":245},[174,2520,2521],{"class":514},"    objectMode",[174,2523,878],{"class":184},[174,2525,2527],{"class":2526},"syTEX"," true",[174,2529,953],{"class":184},[174,2531,2532,2534,2536],{"class":176,"line":252},[174,2533,372],{"class":371},[174,2535,515],{"class":184},[174,2537,383],{"class":184},[174,2539,2540,2542,2544,2546,2548,2551,2554,2556,2559,2561,2563],{"class":176,"line":295},[174,2541,1129],{"class":535},[174,2543,264],{"class":184},[174,2545,1216],{"class":215},[174,2547,220],{"class":514},[174,2549,2550],{"class":184},"{",[174,2552,2553],{"class":514}," id",[174,2555,878],{"class":184},[174,2557,2558],{"class":1139}," 1",[174,2560,208],{"class":184},[174,2562,232],{"class":514},[174,2564,235],{"class":184},[174,2566,2567,2569,2571,2573,2575,2577,2579,2581,2584,2586,2588],{"class":176,"line":300},[174,2568,1129],{"class":535},[174,2570,264],{"class":184},[174,2572,1216],{"class":215},[174,2574,220],{"class":514},[174,2576,2550],{"class":184},[174,2578,2553],{"class":514},[174,2580,878],{"class":184},[174,2582,2583],{"class":1139}," 2",[174,2585,208],{"class":184},[174,2587,232],{"class":514},[174,2589,235],{"class":184},[174,2591,2592,2594,2596,2598,2600,2602,2604],{"class":176,"line":306},[174,2593,1129],{"class":535},[174,2595,264],{"class":184},[174,2597,1216],{"class":215},[174,2599,220],{"class":514},[174,2601,536],{"class":535},[174,2603,232],{"class":514},[174,2605,235],{"class":184},[174,2607,2608],{"class":176,"line":337},[174,2609,395],{"class":184},[174,2611,2612,2614,2616],{"class":176,"line":342},[174,2613,437],{"class":184},[174,2615,232],{"class":219},[174,2617,235],{"class":184},[174,2619,2620,2623,2625,2627,2629,2631,2633,2635,2637,2640,2642,2644,2646,2648,2651],{"class":176,"line":348},[174,2621,2622],{"class":219},"objStream",[174,2624,264],{"class":184},[174,2626,727],{"class":215},[174,2628,220],{"class":219},[174,2630,224],{"class":223},[174,2632,2255],{"class":227},[174,2634,224],{"class":223},[174,2636,192],{"class":184},[174,2638,2639],{"class":377}," obj",[174,2641,744],{"class":180},[174,2643,747],{"class":219},[174,2645,264],{"class":184},[174,2647,752],{"class":215},[174,2649,2650],{"class":219},"(obj))",[174,2652,235],{"class":184},[23,2654,2655],{"id":2655},"总结",[46,2657,2658,2671],{},[49,2659,2660],{},[52,2661,2662,2665,2668],{},[55,2663,2664],{},"流类型",[55,2666,2667],{},"核心方法",[55,2669,2670],{},"用途",[68,2672,2673,2687,2701,2717],{},[52,2674,2675,2680,2684],{},[73,2676,2677],{},[37,2678,2679],{},"Readable",[73,2681,2682],{},[37,2683,1728],{},[73,2685,2686],{},"产生数据",[52,2688,2689,2694,2698],{},[73,2690,2691],{},[37,2692,2693],{},"Writable",[73,2695,2696],{},[37,2697,1732],{},[73,2699,2700],{},"消费数据",[52,2702,2703,2707,2714],{},[73,2704,2705],{},[37,2706,1736],{},[73,2708,2709,2711,2712],{},[37,2710,1728],{}," + ",[37,2713,1732],{},[73,2715,2716],{},"双向通信",[52,2718,2719,2724,2729],{},[73,2720,2721],{},[37,2722,2723],{},"Transform",[73,2725,2726],{},[37,2727,2728],{},"_transform",[73,2730,2731],{},"数据转换（如压缩、加密）",[28,2733,2734,2158],{},[32,2735,2736],{},"关键最佳实践",[582,2738,2739,2745,2751,2754],{},[585,2740,2741,2742,2744],{},"使用 ",[37,2743,569],{}," 组合流，自动处理背压和错误。",[585,2746,2747,2748,2750],{},"避免直接使用 ",[37,2749,565],{}," 而不监听错误。",[585,2752,2753],{},"自定义流时继承正确的基类，并实现必需方法。",[585,2755,2741,2756,2758],{},[37,2757,1748],{}," 检测流结束状态。",[23,2760,2761],{"id":2761},"推荐参考资料",[582,2763,2764,2774,2782],{},[585,2765,2766,2767],{},"Node.js 官方文档：",[2768,2769,2773],"a",{"href":2770,"rel":2771},"https:\u002F\u002Fnodejs.org\u002Fapi\u002Fstream.html",[2772],"nofollow","Stream API",[585,2775,2776,2781],{},[2768,2777,2780],{"href":2778,"rel":2779},"https:\u002F\u002Fnodejs.org\u002Fen\u002Fdocs\u002Fguides\u002Fbackpressuring-in-streams",[2772],"Backpressuring in Streams","（背压指南）",[585,2783,2784],{},"《Node.js 设计模式》第 4 章：流式编程",[2786,2787,2788],"style",{},"html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .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 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 .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 .sVXei, html code.shiki .sVXei{--shiki-light:#E53935;--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 .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .sucvu, html code.shiki .sucvu{--shiki-light:#E53935;--shiki-default:#E36209;--shiki-dark:#FFAB70}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 .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sfo-9, html code.shiki .sfo-9{--shiki-light:#90A4AE;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":170,"searchDepth":238,"depth":238,"links":2790},[2791,2801,2802],{"id":25,"depth":238,"text":26,"children":2792},[2793,2794,2796,2797,2799,2800],{"id":43,"depth":245,"text":44},{"id":561,"depth":245,"text":2795},"二、背压机制与 pipe \u002F pipeline",{"id":1024,"depth":245,"text":1025},{"id":1739,"depth":245,"text":2798},"四、实用工具：stream\u002Fpromises 中的 pipeline 和 finished",{"id":2167,"depth":245,"text":2168},{"id":2456,"depth":245,"text":2457},{"id":2655,"depth":238,"text":2655},{"id":2761,"depth":238,"text":2761},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fend\u002FNodeJs\u002Fcore\u002Fstream","knowledge\u002Fknowledge\u002Fbooklet\u002Fend\u002FNodeJs\u002Fcore\u002Fstream.md","md",{"items":2808},[2809,2813,2817,2821,2825,2829],{"path":2810,"title":2811,"description":2812,"category":10,"score":300},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Ffs","文件系统","Node.js 的 fs 模块提供了与文件系统交互的 API，几乎涵盖了所有标准文件操作。它支持三种风格的 API：同步、回调式异步 和 Promise 式异步。下面详细介绍这些 API 的选择策略、流式读写、文件监视以及常用操作。",{"path":2814,"title":2815,"description":2816,"category":10,"score":300},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fbuffer","缓冲区","Buffer 是 Node.js 全局对象，用于处理二进制数据流（如文件、网络数据）。在 ES6 引入 TypedArray 之前，Buffer 是 Node.js 处理二进制的主要方式；现在 Buffer 实现了 Uint8Arra…",{"path":2818,"title":2819,"description":2820,"category":10,"score":300},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fpath","路径处理","path 模块提供了用于处理和转换文件路径的实用工具。它是 Node.js 核心模块，无需安装即可直接使用。由于不同操作系统（Windows、Linux、macOS）的路径分隔符不同（Windows 使用反斜杠 \\，POSIX 使用正…",{"path":2822,"title":2823,"description":2824,"category":10,"score":300},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fprocess","进程与子进程","Node.js 在单个进程中运行，但通过 process 对象、child_process 模块及 worker_threads 模块提供了对进程的精细控制以及多进程\u002F多线程能力。下面从三个方面展开。",{"path":2826,"title":2827,"description":2828,"category":10,"score":300},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fhttp","网络编程","Node.js 提供了丰富的内置模块，用于构建网络应用。下面从 HTTP\u002FHTTPS、WebSocket、TCP\u002FUDP 以及 DNS 解析四个方面进行深入介绍。",{"path":2830,"title":2831,"description":2832,"category":10,"score":300},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnodejs\u002Fcore\u002Fother","其他常用模块","以下是 Node.js 中几个重要内置模块的详细介绍，涵盖事件触发器、定时器、加密、压缩、操作系统信息和实用工具。",{"series":2834,"title":2835,"items":2836,"index":300,"prev":2850,"next":2851},"booklet\u002Fend\u002Fnodejs\u002Fcore","core",[2837,2839,2841,2843,2845,2847,2849],{"path":2814,"title":2815,"date":2838,"pinned":15},"2025-01-30",{"path":2810,"title":2811,"date":2840,"pinned":15},"2026-06-04",{"path":2826,"title":2827,"date":2842,"pinned":15},"2023-01-27",{"path":2830,"title":2831,"date":2844,"pinned":15},"2020-03-27",{"path":2818,"title":2819,"date":2846,"pinned":15},"2024-03-14",{"path":2822,"title":2823,"date":2848,"pinned":15},"2023-11-10",{"path":7,"title":8,"date":14,"pinned":15},{"path":2822,"title":2823,"date":2848,"pinned":15},null]