为何执行await参数的函数会报错:internalBinding('errors').triggerUncaughtException?

异步调用:

initUserId().then(res => {
    console.log(res)
})

可以写成这样没错吧:

const res = await initUserId()

但是实际在执行的时候(执行npx tsx test05.ts),报错:

node:internal/process/esm_loader:40
      internalBinding('errors').triggerUncaughtException(
                                ^

Error: Transform failed with 1 error:
/Users/john/Desktop/typescript-demo-01/ts-test/test05.ts:20:12: ERROR: Top-level await is currently not supported with the "cjs" output format

请问这是什么问题呢?


完整代码如下:

const initUserId = async (): Promise<string> => {
    const fetchUserId = async(): Promise<string> => {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      return new Promise((resolve, _reject) => {
        setTimeout(() => {
          const userId = '222';
          resolve(userId);
        }, 1000);
      })
    }
  
    const userId = await fetchUserId()
    return userId 
  }

initUserId().then(res => {
    console.log(res)
})

const res = await initUserId()

console.log(res)

export {}

阅读 563
avatarAI BotBETA

问题解释

在你的 TypeScript 代码中,你遇到了一个关于 Top-level await 的错误。Top-level await 指的是在模块顶层(非异步函数内部)直接使用 await 表达式。虽然这个特性在现代 JavaScript 和 TypeScript 中越来越受欢迎,但它并不是所有环境都支持,特别是在使用 CommonJS(cjs)模块系统时。

在你的错误消息中:

Error: Transform failed with 1 error:
/Users/john/Desktop/typescript-demo-01/ts-test/test05.ts:20:12: ERROR: Top-level await is currently not supported with the "cjs" output format

明确指出了 Top-level await"cjs"(CommonJS)输出格式下不支持。

解决方案

  1. 移除或修改顶层的 await
    由于你的代码中已经有使用 .then() 来处理异步结果的部分,你可以完全移除或注释掉顶层的 await 调用。这样,你的代码就只会在 initUserId().then(...) 中异步执行,而不会有 Top-level await 的问题。

    修改后的代码示例:

    const initUserId = async (): Promise<string> => {
        const fetchUserId = async(): Promise<string> => {
          // eslint-disable-next-line @typescript-eslint/no-unused-vars
          return new Promise((resolve, _reject) => {
            setTimeout(() => {
              const userId = '222';
              resolve(userId);
            }, 1000);
          })
        }
    
        const userId = await fetchUserId()
        return userId 
      }
    
      initUserId().then(res => {
          console.log(res)
      })
    
      // 移除或注释掉这一行
      // const res = await initUserId()
      // console.log(res)
    
      export {}
  2. 更改模块系统
    如果你确实需要在模块顶层使用 await,你可以考虑更改 TypeScript 编译器的配置,使用 ES Modules(ESM)而不是 CommonJS。这通常需要在你的 tsconfig.json 文件中设置 "module": "ESNext""module": "ES2020"(取决于你的 Node.js 版本和支持情况)。

    修改 tsconfig.json 示例:

    {
      "compilerOptions": {
        "module": "ESNext",
        "target": "ESNext",
        "esModuleInterop": true,
        "moduleResolution": "node",
        "outDir": "./dist",
        "strict": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
      }
    }

    注意:更改模块系统后,你可能还需要更改你的 Node.js 运行方式或配置,以确保它支持 ES Modules。

结论

根据你的具体需求和运行环境,选择适合你的解决方案。如果你正在一个不支持 Top-level await 的环境中工作,移除或注释掉顶层的 await 调用通常是最简单的解决方案。如果你想要使用现代 JavaScript 特性,可能需要更新你的开发环境或配置。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Microsoft
子站问答
访问
宣传栏