母婴网站的功能设计,专做机酒的网站,wordpress ftp备份,展览展会公司yargs中间件介绍 yargs 是一个用于解析命令行参数的流行库#xff0c;它能帮助开发者轻松地定义 CLI#xff08;命令行接口#xff09;#xff0c;并提供参数处理、命令组织、help文本自动生成等功能。今天我们来学习一下它对中间件的支持。 中间件的API详细信息#xff0… yargs中间件介绍 yargs 是一个用于解析命令行参数的流行库它能帮助开发者轻松地定义 CLI命令行接口并提供参数处理、命令组织、help文本自动生成等功能。今天我们来学习一下它对中间件的支持。 中间件的API详细信息可以查看这里https://yargs.js.org/docs/#api-reference-middlewarecallbacks-applybeforevalidation 在 yargs 中中间件Middleware是一种用于在命令行参数解析过程中插入自定义逻辑的机制。中间件能够在参数验证之前或之后执行允许开发者对 argv 对象进行操作或修改。通过中间件开发者可以对命令行输入进行预处理、验证、转化或者根据业务需求添加自定义操作。 其用途主要是这三个 参数的预处理中间件可以在命令行参数验证之前执行处理或修改 argv比如对输入进行格式化。 参数验证后的处理中间件也可以在参数验证之后执行用于进一步处理解析后的数据或生成特定的输出。 全局中间件中间件可以作用于所有的命令或选项称为全局中间件。通过全局中间件可以对所有命令的输入进行统一处理。 全局中间件 我们先看看api的介绍 .middleware(callbacks, [applyBeforeValidation]) callbacks可以是一个函数或函数列表。每个回调函数都会接收一个对 argv 的引用argv 是一个包含命令行参数的对象。 applyBeforeValidation可选布尔值默认为 false。如果设置为 true则中间件将在验证之前执行但在解析之后。 从这里可以看出其可以定义单个或者多个中间件也可以定义执行顺序。 下面来看几个例子 const mwFunc1 argv console.log(I\m a middleware function);const mwFunc2 argv console.log(I\m another middleware function);yargs .command(myCommand, some command, {}, function(argv){ console.log(Running myCommand!); }) .middleware([mwFunc1, mwFunc2]).parse(); 在这个例子中当从命令行调用 myCommand 时mwFunc1 首先被调用然后是 mwFunc2最后是命令的处理函数。控制台的输出将是 Im a middleware functionIm another middleware functionRunning myCommand! require(yargs/yargs)(process.argv.slice(2)) .middleware(function (argv) { if (process.env.HOME) argv.home process.env.HOME }, true) .command(configure-home, do something with a users home directory, { home: { demand: true, string: true } }, function(argv) { console.info(we know the users home directory is ${argv.home}) } ) .parse() 在这个例子中中间件用于从环境变量中填充 home 目录。由于中间件会接受一个形参argv所以其也可以对该参数做二次修改。 command中间件 command中间件只对当前command生效其会强制把applyBeforeValidation参数设置为false。其接口形式如下 .command(cmd, desc, [builder], [handler]) command中间件只会在command运行的时候执行所以它将晚于全局中间件执行。 require(yargs) .command($0, accept username, () {}, (argv) { // The middleware will have been applied before the default // command is called: console.info(argv); }) .choices(user, [Goofy, Miky]) .middleware(argv { console.info(gots here); const user argv.user; switch (user) { case Goofy: argv.user { firstName: Mark, lastName: Pipe, }; break; } return argv; }) .parse(--user Miky); 如何实现中间件 前面介绍了两种不同的中间件那其内部是如何实现的呢其内部主要依赖middleware.ts来处理全局中间件的添加、应用和管理。它定义了全局中间件的类和相关函数并提供了工具来处理在命令行解析过程中的中间件逻辑。 https://github.com/yargs/yargs/blob/main/lib/middleware.ts GlobalMiddleware 类 GlobalMiddleware 是一个管理全局中间件的类它存储中间件并提供相关操作如添加、冻结、解冻和重置中间件。 globalMiddleware: Middleware[] []存储所有注册的中间件。 frozens: ArrayMiddleware[] []用于存储冻结状态下的中间件组支持回滚到之前的中间件配置。 构造函数 constructor(yargs: YargsInstance) { this.yargs yargs;} 构造函数接受一个 YargsInstance 对象即 yargs 实例用于后续调用命令行解析逻辑。 addMiddleware 方法 addMiddleware( callback: MiddlewareCallback | MiddlewareCallback[], applyBeforeValidation: boolean, global true, mutates false): YargsInstance { 功能该方法允许添加单个或多个中间件。 ** callback**接受中间件函数或中间件数组。 ** applyBeforeValidation**标记中间件是否应该在命令行参数验证之前应用。 ** global**标识中间件是否为全局作用域。 ** mutates**标识中间件是否会修改 argv。 通过该方法添加的中间件会被存储在 globalMiddleware 数组中。 addCoerceMiddleware 方法 addCoerceMiddleware( callback: MiddlewareCallback, option: string): YargsInstance { 功能该方法专门用于处理 coerce 类型的中间件每个选项只能注册一个 coerce 中间件。 操作先过滤掉之前注册的同一选项的 coerce 中间件然后重新添加新的中间件。 freeze 和 unfreeze 方法 freeze() { this.frozens.push([...this.globalMiddleware]);}unfreeze() { const frozen this.frozens.pop(); if (frozen ! undefined) this.globalMiddleware frozen;} ** freeze**将当前的中间件快照保存到 frozens 数组中。 ** unfreeze**从 frozens 中取出最后保存的快照并恢复到 globalMiddleware 中。 reset 方法 reset() { this.globalMiddleware this.globalMiddleware.filter(m m.global);} 功能重置中间件仅保留全局中间件 global: true。 工具方法commandMiddlewareFactory export function commandMiddlewareFactory( commandMiddleware?: MiddlewareCallback[]): Middleware[] { 功能接受命令级中间件数组并将 applyBeforeValidation 设置为 false表示这些中间件默认在验证之后应用。 工具方法applyMiddleware export function applyMiddleware( argv: Arguments | PromiseArguments, yargs: YargsInstance, middlewares: Middleware[], beforeValidation: boolean) { return middlewares.reduceArguments | PromiseArguments( (acc, middleware) { if (middleware.applyBeforeValidation ! beforeValidation) { return acc; } if (middleware.mutates) { if (middleware.applied) return acc; middleware.applied true; } if (isPromise(acc)) { return acc .then(initialObj Promise.all([initialObj, middleware(initialObj, yargs)]) ) .then(([initialObj, middlewareObj]) Object.assign(initialObj, middlewareObj) ); } else { const result middleware(acc, yargs); return isPromise(result) ? result.then(middlewareObj Object.assign(acc, middlewareObj)) : Object.assign(acc, result); } }, argv );} 功能应用所有匹配条件的中间件。 ** argv**代表命令行参数对象可能是普通对象也可能是 Promise。 ** middlewares**传入的中间件数组。 ** beforeValidation**根据此标识决定是否只应用验证前的中间件。 此函数是核心逻辑通过 reduce 迭代应用中间件依次修改 argv 对象。如果 argv 或中间件返回值是 Promise则将其转换为异步逻辑处理。 到这里我们就了解了Yarg是如何实现中间件的了。 中间件知识的迁移 除了Yargs之外Express、Koa等同样也拥有中间件其实我们可以从他们身上总结出一套通用的中间件实现在我们需要的时候可以迁移到其它场景。 中间件的核心是一种可以在处理逻辑链中插入处理函数的技术。它能够接收输入、处理输入并将输出传递给下一个中间件或者返回最终结果。 所以其是对流程的抽象中间接负责承接流程中处理的差异而把调用留给核心主流程。通过中间件的技术我们可以实现如下几点 分离关注点中间件允许将应用中的不同功能模块分开使得每个模块只处理自己关心的部分例如用户身份验证、错误异常处理等 提高代码的可扩展性通过中间件对外暴露处理函数使得系统功能更易于扩展 简化复杂逻辑对于复杂的流程我们可以拆解成多个简单的步骤既增加了每个步骤的控制性又简化了流程操作。例如在处理 HTTP 请求时可以拆解成解析请求体 → 检查身份认证 → 处理权限 → 执行主要业务逻辑 → 格式化返回值 → 记录日志 提高代码的可扩展性中间件可以使系统功能更易于扩展。例如在一个请求处理的生命周期中添加一个新的功能只需要添加一个中间件。无需修改现有的逻辑只需将新中间件插入到处理中间。 中间件的基本结构 function middleware(input, next) { // 对 input 进行处理 const result process(input); // 调用下一个中间件 return next(result);} 通用结构包括 输入通常是某种上下文对象如 req/ res、 argv 等。 输出经过处理后的结果传递给下一个中间件。 ** next**指向下一个中间件的函数或处理器。 中间件的注册与存储 为了灵活添加和管理中间件通常需要将中间件存储在一个有序列表中便于按顺序执行。 通用的中间件存储和注册方法 class MiddlewareManager { constructor() { this.middlewares []; } addMiddleware(middleware) { this.middlewares.push(middleware); } getMiddlewares() { return this.middlewares; }} 中间件执行控制 在某些情况下中间件需要有能力决定是否中止链的执行。这通常通过不调用 next 来实现。 通用模式 function middleware(input, next) { if (shouldStop(input)) { return input; // 不调用 next中止链的执行 } return next(input);} 在 HTTP 请求处理中可能会根据某些条件终止请求处理链并直接返回响应。同样地在命令行工具中某些条件下可以提前结束中间件链的执行。 中间件的管理与重置 中间件链可以根据业务需求进行管理、冻结、解冻和重置这通常用在特定场景下修改中间件或者重置中间件的行为。 通用模式 class MiddlewareManager { constructor() { this.middlewares []; this.frozens []; } freeze() { this.frozens.push([...this.middlewares]); } unfreeze() { const frozen this.frozens.pop(); if (frozen) this.middlewares frozen; } reset() { this.middlewares this.middlewares.filter(m m.global); }} 这种机制允许保存当前的中间件状态并在需要时恢复。 如果需要灵活的配置还可以给中间件附加上option的配置项。 执行中间件链 核心是按顺序调用中间件。可以通过 reduce 或递归的方式将中间件串联起来。每个中间件完成当前处理后需要决定是否将处理权传递给下一个中间件。 通用的执行逻辑 function executeMiddlewares(input, middlewares) { let index -1; function next(currentInput) { index; if (index middlewares.length) { return middlewares[index](currentInput, next); } return currentInput; // 所有中间件处理完成后的结果 } return next(input);} 这里的 next 函数控制中间件的执行顺序每次调用都会进入下一个中间件。 支持异步中间件 在实际应用中很多中间件需要处理异步操作如数据库查询、HTTP 请求等。因此中间件链需要支持异步操作。 通用的异步中间件支持 async function executeAsyncMiddlewares(input, middlewares) { let index -1; async function next(currentInput) { index; if (index middlewares.length) { const result await middlewares[index](currentInput, next); return result; } return currentInput; } return next(input);} 这可以确保异步中间件正确地等待 Promise 解决后再执行下一个中间件。 大白话总结一下中间件就是管理一堆函数并在特定的时候调用这些函数。 总结 yargs 的中间件为命令行工具的开发提供了极大的灵活性。通过中间件开发者可以轻松地定制参数解析和处理的过程适用于复杂的命令行应用场景。 我们也可以将中间件的思维迁移到我们的业务开发中对于复杂的流程做好模块拆分就可以增加一个Middlewares来管理对应模块的处理函数并在流程需要的时候调用他们。 本文由 mdnice 多平台发布