ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

learnyounode Make It Modular 练习精讲:用 Node.js 模块重构目录过滤程序(含验证机制源码解析)

learnyounode Make It Modular 练习精讲:用 Node.js 模块重构目录过滤程序(含验证机制源码解析) 教程CLI【免费下载链接】learnyounodeLearn You The Node.js For Much Win! An intro to Node.js via a set of self-guided workshops.项目地址https://gitcode.com/gh_mirrors/le/learnyounode点击查看免费下载本篇技术指南围绕 learnyounode 自学工作坊中的Make It Modular练习展开其土耳其语文案见 exercises/make_it_modular/problem.tr.md英文原版见 exercises/make_it_modular/problem.md。该练习是「Filtered LS按扩展名过滤目录文件」的进阶版同样要求打印目录中按扩展名过滤后的文件列表但必须拆分成两个文件——一个可复用的模块文件与一个调用该模块的主程序文件从而系统性地掌握 Node.js 的 CommonJS 模块系统、module.exports单函数导出、require(./...)相对路径引入以及 Node 惯用的err, data回调约定。阅读完本文后你将能独立写出通过learnyounode verify校验的模块化程序并理解该练习背后的自动验证原理。练习背景从同步到异步、从单体到模块Make It Modular 在 learnyounode 的课程序列中处于「文件系统操作」与「异步 I/O」板块的收尾位置。在此之前你已经完成了以下铺垫练习MY FIRST I/O用同步 API如fs.readFileSync读取文件内容FILTERED LS用fs.readdir列出目录按扩展名过滤并逐行打印MY FIRST ASYNC I/O改用异步 API 并理解回调时序。Make It Modular 的题目与 Filtered LS几乎完全相同唯一的差异是引入了模块modules概念你必须把「读取目录 按扩展名过滤」的核心逻辑放进一个独立模块文件再由主程序调用。以土耳其语练习文案为例你需要创建两个文件benimmodulum.js对应英文版的mymodule.js模块文件负责大部分工作moduler-yap.js对应英文版的make-it-modular.js主程序文件。提示各语言版本的题目内容一致仅文件名与语言措辞不同。英文原版要求创建make-it-modular.js和mymodule.js土耳其语版则使用上述两个土语文件名。完整需求拆解程序行为程序接收两个命令行参数参数位置含义示例process.argv[2]目录的完整路径/home/user/dataprocess.argv[3]用于过滤的文件扩展名不含点号md输出要求把目录中所有扩展名匹配的文件名逐行打印到终端每个文件一行并且必须使用异步 I/O——fs.readdir()而不是fs.readdirSync()。模块的三参数函数契约benimmodulum.js必须导出一个函数该函数按顺序接收三个参数目录名directory name文件扩展名字符串extension filter string回调函数callback function。关键约束在把扩展名传给模块之前不得以任何方式修改它——不要加.前缀不要转成正则表达式直接原样传递。真正的过滤处理应放在模块内部完成例如在模块内拼接出. filterStr。node(err, data) 回调约定模块导出的函数必须遵循 Node.js 惯用的回调约定无错误时callback(null, data)第一个参数传null第二个参数传过滤后的文件列表数组形式出错时例如fs.readdir()内部出错callback(err)错误对象作为第一个也是唯一的参数传给回调。职责边界谁负责打印两条严格的职责边界模块文件内绝对不要直接打印到控制台不碰 stdout打印文件列表只能发生在主程序moduler-yap.js中当错误冒泡到主程序时主程序负责检查错误并向终端打印一条信息明确的错误消息例如console.error(There was an error:, err)。模块必须遵守的四条契约题目明确列出模块正确性的四项要求这也是模块能被任何遵守同一契约的调用方其他学习者或 learnyounode 验证器直接复用的前提导出一个按前述描述精确接收参数的函数恰好调用一次回调携带错误或数据不改变其他任何东西例如全局变量或 stdout即不产生副作用处理所有可能发生的错误并把它们传给回调函数。动手实现模块文件 benimmodulum.js单函数导出module.exports 赋值创建模块的关键语法是把函数直接赋值给module.exports对象覆盖其默认内容module.exports function (args) { /* ... */ }也可以先定义命名函数再把函数名赋值给module.exportsfunction filterFiles (dir, filterStr, callback) { /* ... */ } module.exports filterFiles完整参考实现仓库自带的官方参考答案位于 exercises/make_it_modular/solution/solution_filter.js仅 17 行是模块实现的最小范本use strict const fs require(fs) const path require(path) module.exports function (dir, filterStr, callback) { fs.readdir(dir, function (err, list) { if (err) { return callback(err) } list list.filter(function (file) { return path.extname(file) . filterStr }) callback(null, list) }) }逐行解读这段参考实现异步读取fs.readdir(dir, callback)是异步 API回调签名本身就是(err, files)天然契合后续的(err, data)约定错误短路径if (err) { return callback(err) }——出错时立即把错误原样交给回调并提前返回不再继续执行过滤逻辑path.extname(file)返回文件扩展名含点号如.md与. filterStr精确比较。由于模块接收的filterStr不含点号这里的拼接发生在模块内部完全符合「外部不修改扩展名参数」的要求成功路径callback(null, list)无错误时第一个参数传null第二个参数传过滤后的数组。该实现严格满足四条契约导出三参数函数、回调只调用一次、不碰 stdout、所有fs.readdir错误都交给回调。动手实现主程序文件 moduler-yap.js引入本地模块require 与 ./ 前缀使用本地模块与使用内置模块的方式一致都是调用require()——你早已熟悉require(fs)加载fs模块唯一区别是本地模块路径必须以./开头const mymodule require(./benimmodulum.js)细节说明这里的.js扩展名是可选的实践中经常省略require(./benimmodulum)同样有效因为模块导出的是单个函数所以mymodule这个变量本身就是可调用的函数直接mymodule(dir, ext, callback)即可。完整参考实现主程序参考实现见 exercises/make_it_modular/solution/solution.jsuse strict const filterFn require(./solution_filter.js) const dir process.argv[2] const filterStr process.argv[3] filterFn(dir, filterStr, function (err, list) { if (err) { return console.error(There was an error:, err) } list.forEach(function (file) { console.log(file) }) })主程序的结构清晰体现了「错误检查 早返回early-return」的惯用写法从process.argv[2]、process.argv[3]取出目录与扩展名调用模块函数传入回调回调内先检查错误有错立即return console.error(...)并退出回调无错误时对list数组逐项console.log打印一行一个文件。回调中的错误检查与早返回范式题目提示中专门强调在回调函数里检查错误并做 early-return 是良好习惯。文档给出的通用范式如下function bar (callback) { foo(function (err, data) { if (err) { return callback(err) } // 早返回early return出错立即把错误透传出去 // ... 没有错误继续用 data 做想做的事 // 一切正常把 null 作为错误参数传给回调 callback(null, data) }) }这个模式保证了回调在整个链路中只会以「携带错误」或「携带数据」两种方式被调用一次不会出现「既报错又返回数据」或「重复回调」的歧义这正是第 2 条契约callback 恰好调用一次的实现基础。验证机制源码级解析learnyounode 如何判定你的模块理解自动验证器的检查逻辑能帮你写出一次通过的实现。相关源码位于 exercises/make_it_modular/verify.js 与 exercises/make_it_modular/exercise.js。1. 练习夹具准备exercise.js验证前exercises/make_it_modular/exercise.js 会在系统临时目录创建_learnyounode_pid测试目录并把 exercises/filtered_ls/file-list.json 中列出的文件名如learnyounode.dat、README.md、CHANGELOG.md、md、w00t.txt、data.json、words.dat等 15 个文件逐一写入该目录同时通过this.submissionArgs.unshift(md)和unshift(testDir)把「测试目录 扩展名md」注入到被验证程序的process.argv中。注意file-list.json中有一个名为md的无扩展名文件它专门用来检验你的过滤实现——若你的程序只做endsWith(.md)之类的粗糙匹配就会把md这个文件也误报出来。正确做法是像官方解答那样使用path.extname()。2. 验证器检查清单verify.jsexercises/make_it_modular/verify.js 按以下顺序逐步核验你的模块validateModule函数导出的是函数typeof mod ! function即判失败对应「单函数导出」要求形参个数 ≥ 3mod.length 3判失败函数.length是形参个数对应「三参数函数」要求错误透传验证器会临时替换fs.readdir让它强制回调一个Error(testing)然后调用你的模块检查回调收到的err是否就是那个错误对象——对应「错误传给回调」契约回调确实被调用通过setTimeout在 300ms 后复查回调是否被使用未调用则判fail.mod.missing_callback第二个参数必须是数组!Array.isArray(list)判失败返回值数量与内容精确匹配验证器把file-list.json中匹配\.md$的文件数与你的结果比较。若数量对不上还会二次检查——用.dat作为扩展名再调用一次你的模块探测你是否犯了「把.前缀拼进传给模块的扩展名」的典型错误fail.mod.dont_use_dot、fail.mod.dotExt元素内容一致排序后逐项比对数组内容。此外验证器通过 exercises/my_first_io/wrap.js 的 fs 调用包装检测你的程序是否使用了任何Sync后缀的同步 API如fs.readdirSync——一旦发现同步调用立即判失败强制执行「必须使用异步 I/O」的题目要求。同时通过 exercises/make_it_modular/wrap-requires.js 记录你的主程序require了哪些模块确保你确实引入了自定义模块verifyModuleUsed而不是把过滤逻辑全部内联在主程序里蒙混过关。运行与验证在 learnyounode 交互菜单中选择「MAKE IT MODULAR」进入本练习后用{appname}占位符对应的真实命令即learnyounode验证你的主程序文件$ learnyounode verify moduler-yap.js执行流程验证器会先运行你指定的主程序用「测试目录 md扩展名」作为实际参数驱动它检查终端输出是否与期望结果一致随后再按上文清单逐个检查你require进来的模块文件是否满足四项契约。全部通过即显示 PASS。建议的本地自查步骤不依赖验证器# 1. 直接运行观察输出 $ node moduler-yap.js ./some-dir md # 2. 传入不存在的目录观察错误分支是否打印信息 $ node moduler-yap.js ./no-such-dir md常见错误与避坑清单对照验证器源码容易翻车的典型错误如下错误类型表现正确做法同步 API使用fs.readdirSync一律改用fs.readdir异步版本扩展名带点号把.md传给模块原样传md在模块内部拼接.前缀过滤不精确用endsWith(.md)匹配用path.extname(file) . filterStr模块内打印模块文件直接console.log打印只放在主程序回调中错误未透传出错时忽略 err 继续执行if (err) { return callback(err) }回调多次调用出错和成功路径都触发回调用早返回保证只调用一次未真正 require 模块逻辑全内联在主程序确保主程序require(./benimmodulum.js)形参不足三个导出两个参数的函数函数签名必须含dir, filterStr, callback模块化的工程意义这个练习的落点不仅是语法而是可复用接口的设计。正如题目所述遵循四条契约的好处在于你的模块可以被任何同样遵守err, data约定的人直接拿来用——无论是其他 learnyounode 学习者还是自动验证器。这正是 Node.js 生态中数以万计的 npm 包得以自由组合的基石通过module.exports暴露最小化的函数接口通过require(./...)在文件之间建立显式依赖通过回调约定在异步世界里统一错误与数据的传递方式。掌握了 Make It Modular你就掌握了后续一切 Node.js 工程化开发的三块基石模块拆分、异步回调约定、错误处理范式。赞分享教程CLI【免费下载链接】learnyounodeLearn You The Node.js For Much Win! An intro to Node.js via a set of self-guided workshops.项目地址https://gitcode.com/gh_mirrors/le/learnyounode点击查看免费下载相关推荐learnyounode 实战make-it-modular 练习全解——用 Node.js 模块化重构目录过滤程序learnyounode 实战make it modular 练习全解——用 Node.js 模块化重构目录过滤程序 本文是 learnyounode 教程中教程CLIlearnyounode make-it-modular 练习精讲用 Node.js 模块化与 node(err, data) 回调约定重构文件过滤程序learnyounode make it modular 练习精讲用 Node.js 模块化与 node err, data 回调约定重构文件过滤程序 本指南教程CLIlearnyounode MAKE IT MODULAR 练习全解用 Node.js 模块化与回调契约实现目录文件过滤learnyounode MAKE IT MODULAR 练习全解用 Node.js 模块化与回调契约实现目录文件过滤 导读 本篇文章围绕 learnyoun教程CLI上一篇如何在5分钟内搭建claude-code.nvim从安装到第一个AI辅助编码会话下一篇MAS 免费激活 Windows 与 Office 完整指南从下载到完成只需 3 步创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表