Node.js 从 v16 升级至 v20 后,若发现 async 函数返回值显示为 Promise { <pending> },这并非 Node.js 内核的行为变更,而是代码中遗漏 await 或依赖库升级导致接口异步化所致。
核心结论:async 函数在所有现代 JavaScript 环境中均返回 Promise,显示 Pending 说明 Promise 尚未被解析或未使用 await 获取结果,需排查代码适配问题。
- 确认调用处:检查调用 async 函数处是否遗漏了 await 关键字。
- 更新依赖:将第三方依赖库更新至支持 Node.js v20 的版本。
- 验证结果:通过 console.log 打印 await 后的结果确认值已解析。
核心原因分析
在 JavaScript 标准规范中,async 函数始终返回一个 Promise 对象,这一点在 Node.js v16 到 v20 之间没有改变。如果你在控制台看到 Promise { <pending> },通常是因为以下两个原因之一:
第一,代码直接打印了函数调用结果而没有等待。例如使用 console.log(asyncFn()) 而不是 console.log(await asyncFn())。在 Node.js 新版本中,控制台对 Promise 的 inspect 输出可能更加明确,导致之前被忽略的未 await 情况现在更明显。
第二,依赖库升级导致行为变化。某些库在适配新版本 Node.js 时,可能将原本同步的函数改为了异步函数,或者改变了内部 Promise 的处理逻辑,导致调用方原本不需要 await 的代码现在必须 await 才能拿到值。
查阅 Node.js 官方 CHANGELOG 可知,v20 并未修改 async 函数的基础返回机制,这更多是运行时期望值与实际返回类型不匹配的问题。
排查与修复步骤
按照以下步骤逐步排查,每一步完成后请重启服务验证。
1. 检查调用处是否缺失 await
在代码中搜索该函数名,确保调用处使用了 await。如果是顶层代码,确保文件后缀为.mjs 或 package.json 中设置了 "type": "module" 以支持顶层 await。
// 错误示例
const result = myAsyncFunc();
console.log(result); // 输出 Promise { <pending> }
// 正确示例
const result = await myAsyncFunc();
console.log(result); // 输出实际值2. 检查依赖包兼容性
使用 npm ls 查看是否有依赖包报错或不兼容。升级主要依赖包到最新版本,查看其 changelog 是否有破坏性更新。
npm update
npm ls3. 检查测试 runner 配置
如果你使用 Node.js 内置的 test runner,v18 之后行为更加严格。确保异步测试函数正确 await 或返回 Promise。
// 测试文件示例
import { test } from 'node:test';
test('异步测试', async () => {
const data = await asyncFunc();
// 确保这里 await 了
});依赖库变更案例
在实际升级过程中,部分常用库的 major 版本更新可能伴随 API 异步化。例如某些数据库客户端或 HTTP 请求库,在旧版本中可能支持同步获取配置或连接状态,而在新版本中强制要求异步初始化。
若发现升级某依赖后出现 Pending 状态,请查阅该依赖的 Migration Guide,确认是否有函数签名从同步变为异步的情况,并相应调整调用代码。
验证方法
修改代码后,通过以下方式确认问题已解决:
- 运行脚本,观察控制台输出是否不再是 Promise { <pending> },而是具体的数据值。
- 检查应用日志,确认没有 UnhandledPromiseRejectionWarning 警告。
- 如果是 API 服务,使用 curl 或 Postman 请求接口,确认响应体包含实际数据而非空对象或错误。
常见陷阱
- 顶层 await 限制:在 CommonJS 模式(默认)下不支持顶层 await,强行使用会导致语法错误,需改为 ESM 或包裹在 async IIFE 中。
- 回调函数混用:部分旧代码可能混合使用回调和 Promise,升级后可能导致执行顺序混乱,建议统一改为 async/await。
- 测试环境差异:本地 REPL 环境与生产脚本环境对 Promise 的展示可能不同,不要仅依赖 REPL 的输出判断。
参考来源
- Node.js 官方发布说明,CHANGELOG.md,https://github.com/nodejs/node/blob/main/CHANGELOG.md
- MDN Web Docs,async function,https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function