如何在 Node+Typescript+VSCode 中查找 Async 函数调用中缺少的 Await?

Posted

技术标签:

【中文标题】如何在 Node+Typescript+VSCode 中查找 Async 函数调用中缺少的 Await?【英文标题】:How to find missing Await on Async function calls in Node+Typescript+VSCode? 【发布时间】:2018-03-29 15:06:53 【问题描述】:

我们在节点应用程序 b/c 中部署了错误,我们忘记在异步函数调用前加上“await”。

例子:

const getUsers = async () => db.query('SELECT * from Users');

const testMissingAwait = async () => 
  const users = getUsers(); // <<< missing await
  console.log(users.length);
;

testMissingAwait();

有没有一种简单的方法可以找到缺少 await 关键字的异步函数调用?

如果做不到这一点,编写一个自动标记这些的 Visual Studio Code 扩展需要付出多少努力? (如果有人能指出我正确的方向,我愿意解决)。

【问题讨论】:

该功能甚至需要异步吗?它有什么收获吗? (getUsers) 你在这个项目中使用打字稿吗?如果是这样,它应该在编译时捕获该错误,因为类型 Promise&lt;xxx&gt; 没有属性“长度”。 @CRice 如果您执行“users.length”则有效,因为 Promise 没有属性“length”,但如果您忘记等待没有返回值的异步函数,那么 Typescript 将无济于事你用这个机制。有谁知道是否有一个 Typescript 设置(或其他 linter)可以检测到您没有等待的异步函数调用并将它们标记为可能的错误(您可以使用指令显式忽略仅当您想要启动异步工作时而不是等待它)? 实际上似乎有一个 tslint 规则来检测称为 no-floating-promises 的“浮动”承诺 - palantir.github.io/tslint/rules/no-floating-promises, github.com/palantir/tslint/pull/1632 ESLint 中也有这方面的东西吗? require-await 不是吗。 【参考方案1】:

TypeScript 已经这样做了

// users is a Promise<T>
const users = getUsers(); // <<< missing await

// users.length is not a property of users... then and catch are
console.log(users.length);

您可以找到不会被告知您的错误的情况 - 类型兼容的情况,例如我在这里错过了等待:

function delay(ms: number) 
    return new Promise<number>(function(resolve) 
        setTimeout(() => 
            resolve(5);
        , ms);
    );



async function asyncAwait() 
    let x = await delay(1000);
    console.log(x);

    let y = delay(1000);
    console.log(y);

    return 'Done';


asyncAwait().then((result) => console.log(result));

因为console.log 不会导致我的数字和我的承诺之间出现任何类型不兼容,所以编译器无法判断我犯了错误。

这里唯一的解决方案是类型注释......但如果你要忘记等待,你很可能会忘记类型注释。

let y: number = delay(1000);

【讨论】:

【参考方案2】:

TypeScript 编译器没有为此提供编译器选项。但是,TSLint 4.4 提供了检测浮动承诺的选项。您可以阅读这篇博文以获得更详细的答案:Detect missing await in typescript

下载 TSLint:

npm install -g tslint typescript

配置 TSLint:


    "extends": "tslint:recommended",
    "rules": 
        "no-floating-promises": true
    

运行 TSLint:

tslint --project tsconfig.json

如果您的代码中有浮动承诺,您应该会看到以下错误:

错误:F:/Samples/index.ts[12, 5]:必须正确处理承诺

【讨论】:

是的,可以,但是 VSCode 问题选项卡显示的错误比手动运行 tslint 少(例如,当您忘记问题选项卡中不存在等待时出现 tslint 错误) 我的 VS Code 也没有显示 ESLint cli 可以检测到的所有错误。安装 ESLint VS Code 插件解决了这个问题。【参考方案3】:

tslint is deprecated 但typescript-eslint 对此有一个规则:no-floating-promises

此规则禁止在未适当处理其错误的情况下在语句中使用类似 Promise 的值...处理 Promise 值语句的有效方法包括 awaiting、返回以及使用两个参数或 @ 调用 .then() 987654331@ 一个参数。

要使用它,您需要设置 typescript-eslint:

    安装依赖项

    npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
    

    修改您的.eslintrc 文件

    这些是最低要求的设置;有关更多选项,请参阅文档 (https://typescript-eslint.io/docs/linting/linting):

    
      "parser": "@typescript-eslint/parser",
      "parserOptions":  "project": "./tsconfig.json" ,
      "plugins": ["@typescript-eslint"],
      "rules": 
        "@typescript-eslint/no-floating-promises": ["warn"]
      
    
    

    (我将其设置为warn,因为有时您可能希望调用返回Promise 的函数而不使用await。但如果您愿意,可以将其设置为error。)

下次运行 eslint 时,您应该会看到已应用的规则:

$ npm run lint
...
./src/database/database.ts
  219:7  warning  Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator  @typescript-eslint/no-floating-promises

由于您特别提到了 VS Code,这也与 ESLint plugin 很好地集成:

【讨论】:

以上是关于如何在 Node+Typescript+VSCode 中查找 Async 函数调用中缺少的 Await?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Node 和 TypeScript 获取异步堆栈跟踪?

如何在 Typescript 中获取 node_modules 包类型

如何使用 TypeScript 导入自定义 node.js 插件模块

Node.js 和 Typescript,如何动态访问导入的模块

如何使用 Node.js 包中的 TypeScript 键入信息?

如何清理 Node.js 和 Typescript 中的响应正文