多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Node.js Writable可写流入门到精通:streamify-your-node-program拆解_write、next回调与finish事件的完整生命周期

Node.js Writable可写流入门到精通:streamify-your-node-program拆解_write、next回调与finish事件的完整生命周期 Node.js Writable可写流入门到精通streamify-your-node-program拆解_write、next回调与finish事件的完整生命周期【免费下载链接】streamify-your-node-program对Node.js中 stream模块的学习积累和理解项目地址: https://gitcode.com/gh_mirrors/st/streamify-your-node-program在streamify-your-node-programNode.js stream 模块学习积累项目中Writable 可写流是理解数据“下游消耗”的关键一环。本文带你快速掌握Node.js Writable 可写流的完整生命周期从实现_write方法、调用next回调声明写入完成到监听finish事件确认全部数据落盘一篇看懂 Writable 可写流的入门与进阶细节。1. 什么是 Writable 可写流一句话理解可写流Writable扮演数据管道中的“下游”负责消耗上游提供的数据。在 Node.js 的 stream 模块中四种流各司其职流类型角色核心方法/事件Readable 可读流上游生产数据push/data、endWritable 可写流下游消耗数据write/_write、finishDuplex 双工流既可读又可写继承两者Transform 转换流边读边转再写_transform典型的 Writable 场景fs.createWriteStream写文件、http.ServerResponse响应请求、process.stdout输出到终端。2. 创建 Writable 流两种实现_write的方式实现一个可写流本质就是提供_write(data, encoding, next)方法每次调用writable.write(data)内部就会触发_write处理数据。方式一构造时传配置对象推荐简洁var Stream require(stream) var writable Stream.Writable({ write: function (data, _, next) { console.log(data) process.nextTick(next) }, }) writable.write(a) writable.write(b) writable.end()方式二直接赋值_writeES6 class 场景常用class PrintUpperCase extends Writable { _write(buf, enc, next) { process.stdout.write(buf.toString().toUpperCase()) process.nextTick(next) } } 对应示例代码可参考example/objectMode/writable.js配置对象方式、example/implement/writable.jsclass 继承方式。⚠️ 两个必须记住的要点调用write(data)只是“送入”数据真正处理发生在_write必须调用end()告知可写流“数据已全部写入”否则生命周期无法收尾。3. next 回调Writable 流的“心跳”_write的第三个参数next是整条生命周期的枢纽上游调用write(data)→ 触发_write你完成底层写入可以是异步的比如fs.write调用next()声明“本块写入完成”流才会处理缓存中的下一块。如果忘记调用next()整个写入队列就会永久卡住——这是新手最常见的 Bug。推荐用process.nextTick(next)保证异步时序正确。另外write(data, cb)还支持传入回调在对应数据块处理完成后执行方便做精确的完成追踪writable.write(a, function () { console.log(write a) }) 示例example/writable.js。4. finish 与 prefinish 事件完整生命周期拆解与 Readable 的end事件类似Writable 有两个事件表示“写完”write(a) → write(b) → write(c) → end() ↓ _write(a) → next() ↓ _write(b) → next() ↓ _write(c) → next() ← 最后一次 next 执行完 prefinish ← 底层写入全部完成缓存清空 write 回调全部执行 finish ← 整个写操作彻底结束prefinish所有数据均已写入底层即最后一次_write的next已执行缓存中再无待写数据finish在 prefinish 之后触发表示所有write(data, cb)传入的回调均已执行完。实践建议一般监听finish事件来判断写操作完成如关闭数据库连接、输出统计信息。 完整可运行示例example/event-finish.js运行即可看到prefinish → write a/b/c 回调 → finish的触发顺序配套讲解见docs/writable.md的“finish事件”章节。5. 进阶back-pressure 背压与 highWaterMarkWritable 内部维护一个待写入数据队列缓存其长度由highWaterMark约束当队列长度超过 highWaterMark时write(data)会返回false上游据此暂停写入并监听drain事件缓存清空后触发再继续这正是pipe自动实现的“从 push 到 pull”下游快时持续写下游慢时自动暂停上游形成背压闭环避免内存暴涨。打个比方手动data → write是“仰头猛灌”而pipe是“用吸管喝咽下去才继续吸”。 背压原理讲解见docs/highWaterMark.md“Writable中的缓存”一节与docs/pipe.md“从push到pull”一节实战示例见example/principle/back-pressure/pipe.js与example/highWaterMark.js。6. objectMode让 Writable 写入任意对象默认非 objectMode下write只接受 String/Buffer且_write收到的 chunk 一定是Buffer如Buffer 61。设置Writable({ objectMode: true })后write可传入任意类型_write中拿到的就是原对象本身——非常适合在管道中传递结构化数据。 对比示例example/objectMode/writable.js与example/objectMode/writable-objectMode.js详解见docs/objectMode.md的“对Writable的影响”一节。7. 新手避坑清单 ✅常见问题正确做法忘记调用next()导致流卡死写入完成后异步也要必须调用next()出错时传next(err)忘记调用end()finish 永不触发数据写完一定调用writable.end()忽略write返回值返回false时暂停上游监听drain再续写非 objectMode 下期望拿到 String默认拿到的是 Buffer需要对象请开启objectMode下游不消费导致整条管道停滞确保下游正常写入并触发drain8. 小结一张图记住完整生命周期write(data)→ 触发_write→ 调用next()→ 缓存清空后drain→end()→prefinish底层写完→finish回调写完掌握 Writable 可写流只需记住三件套_write处理数据、next驱动节奏、finish宣告完成。配合项目中的示例代码example/目录与文档docs/writable.md、docs/implement-streams.md从入门到精通的 Node.js 可写流之路已经铺平动手跑一遍示例背压与事件时序自然会内化于心。【免费下载链接】streamify-your-node-program对Node.js中 stream模块的学习积累和理解项目地址: https://gitcode.com/gh_mirrors/st/streamify-your-node-program创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表