【发布时间】:2020-04-24 07:21:01
【问题描述】:
我知道这个问题一直是dealtwithso many times,但它们似乎都没有解决可靠检测悬空承诺的问题(即使是那些正确解决的问题)。
所以我希望能够找到一种方法(无论是在运行时还是在静态时更好)来根除“悬空承诺”,尤其是这个类:
async function a() {
... do some async operation ...
}
async function b() {
a(); // forgot to call await on it
}
我不小心忘记在一个函数上等待,而某些异步执行的任务没有得到等待。通常这些类型的错误不会引发异常,所以我不能只使用“unhandledRejection”并收工。
在经过大量绝望尝试之后,我现在只需要一种方法来在(最佳)静态/编译/lint 时间或运行时检测这种错误模式。假设我有良好的测试覆盖率,我认为运行时应该可以工作。
tl;dr 基本上,我正在寻找一些可以执行以下操作的代码:
Error: Potential dangling promise detected!
...
at b (/dangling.js:5:3)
对于每个悬空的承诺
我的思考过程
我首先尝试找到一些有助于检测这些东西的静态分析库(理论上应该是可能的,但我没有找到这样的东西)。不久前,我记得在 stackoverflow 的深处发现了一些关于使用一些打字稿检查器来检查悬空承诺的东西,尽管现在我再也找不到它了 :(。虽然当时将整个代码库更改为打字稿是不行的-go。(后来我知道你can actually 使用 tsc 对 javascript 进行类型检查(假设你在 cmets 中做了一些类型注释))
目前我之前使用的是 node 版本 11,所以我考虑使用 node.js 的 async_hooks API 并尝试监听事件(显然简单的猴子修补 Promise 构造函数是行不通的,因为 node.js 绕过了 Promise创建 Promise 对象以从异步函数返回时的构造函数)。使用节点 v11,经过一点code hackery here 之后,它似乎工作了(虽然它不是很有效,因为它在 v8 引擎中丢弃了很多承诺优化,但它确实完成了工作)。在整个操作中出现了一个小问题,因为我仍然必须对 Promise API 的 then/catch/finally 函数进行修补,以检查我们当前是否正在调用该函数(以某种方式检测一些悬空的 Promise)。
现在进入节点 v12(显然我需要它来处理某些其他正在破坏的事情),现在骇客(不出所料)完全崩溃了。仔细查看version diffs 后,似乎他们optimized the await/async implementation。缩小原因后,似乎 await 不再调用 promise 的 then 函数,而只是直接做一些原生的恶作剧(真的是什么)。
现在我实际上有点迫切需要一些解决方案(也许如果 Typescript 有某种方式对这些悬空的承诺进行类型检查,那么启用此检查的选项是什么?我知道(经过测试)tsc 不会这样做默认)。
【问题讨论】:
-
可以不用eslint插件吗?例如:npmjs.com/package/eslint-plugin-promise
-
嗯,很有趣...我会调查一下,谢谢
-
TSLint 包含适用于这种情况的 no-async-without-await 规则:palantir.github.io/tslint/rules/no-async-without-await
-
@ theKidOfArcrania - 正如您所指出的,这样做需要某种分析工具,最好是带有类型信息的分析工具。
typescript-eslint就是这样一种工具,它是 TSLint 的继任者。它适用于 TypeScript。我不认为它有一个规则可以做你想要的,但应该可以为一个插件编写一个插件,因为它确实有类型信息,所以你可以检查一个函数是否返回一个承诺并检查它是否是awaited。边缘情况可能很棘手,例如将async函数传递给map以构建... -
为了解决检测dangling promises的问题,首先需要解决检测promises的问题,这本身并不意味着鉴于任何函数都可以返回 Promise,而不仅仅是 AsyncFunctions。
标签: javascript node.js promise