如何在调用层级中正确使用neverthrow结合async/await?
你完全没说错——当前的写法确实绕了弯路,neverthrow 提供了更贴合其设计理念的简洁方式来串联 ResultAsync 操作,不需要手动把逻辑包进 Promise 再转 ResultAsync。核心思路是利用 ResultAsync 内置的链式方法(比如 andThen、tap、map)或者结合 asyncAndThen 来直接处理异步流,避免手动的 isErr() 检查和 throw。
方案一:用链式方法串联操作(最符合函数式风格)
ResultAsync 的 andThen 方法专门用于串联依赖前一个操作成功的异步 Result 流程,tap 用于执行副作用(比如给实例属性赋值),map 用于转换成功值。这样可以完全摆脱手动错误检查:
public init(): ResultAsync<null, AppError> { return this.retrieveOidcConf() // 执行副作用:保存OIDC配置(tap不修改Result的值,仅执行操作) .tap(oidcConf => { this.oidcConf = oidcConf; }) // 前一步成功后,调用retrieveKey(返回ResultAsync) .andThen(() => this.retrieveKey()) // 执行副作用:保存密钥 .tap(key => { this.key = key; }) // 把最终成功值转换为null,匹配方法返回类型 .map(() => null); }
方案二:结合 async/await 简化写法
如果你更习惯 async/await 的线性写法,也可以用 asyncAndThen 方法(它支持传入 async 函数,自动处理内部的 ResultAsync),或者直接在 ResultAsync.fromPromise 里用 async 函数,利用 unwrap() 简化错误处理(错误会自动被捕获并转为 Err):
public init(): ResultAsync<null, AppError> { return this.retrieveOidcConf() .asyncAndThen(async (oidcConf) => { this.oidcConf = oidcConf; // 直接await ResultAsync,unwrap()会在成功时返回值,错误时抛出(被asyncAndThen捕获转为Err) const key = await this.retrieveKey().unwrap(); this.key = key; return null; }); }
或者更直接的线性写法:
public init(): ResultAsync<null, AppError> { return ResultAsync.fromPromise( (async () => { const oidcConf = (await this.retrieveOidcConf()).unwrapOrThrow(); this.oidcConf = oidcConf; const key = (await this.retrieveKey()).unwrapOrThrow(); this.key = key; return null; })(), e => e as AppError ); }
顺带优化你的 retrieveOIDCConf 方法
你的 retrieveOIDCConf 写法也可以简化,把数据验证和错误处理拆成链式调用,避免在 then 里 throw:
private retrieveOIDCConf(): ResultAsync<OIDCConf, AppError> { return ResultAsync.fromPromise( axios.get(confService.oauthConfig.oidcConfURI), (e) => { logger.error(`Could not retrieve OIDC configuration from ${confService.oauthConfig.oidcConfURI}`, e); return new AppError({ /* 你的错误配置 */ }); } ) // 提取响应数据 .map(res => res.data) // 验证数据格式,返回新的ResultAsync .andThen(data => { if (validateOIDCConf(data)) { logger.info(`Successfully retrieved OIDC configuration from ${confService.oauthConfig.oidcConfURI}`); return ResultAsync.ok(data); } else { logger.error(`OIDC configuration returned in unexpected format from ${confService.oauthConfig.oidcConfURI}`); return ResultAsync.err(new AppError({ /* 你的错误配置 */ })); } }); }
核心思路总结
neverthrow 的设计目标就是让你摆脱手动的错误分支判断,通过链式方法或者 async/await 结合内置工具,让错误流自动传递。你之前的写法相当于绕回了传统 Promise 的 try/catch 模式,没有充分利用 ResultAsync 的优势。
内容的提问来源于stack exchange,提问作者badnun872

