等待/异步如何处理未解决的承诺

hbt*_*hbt 4 javascript asynchronous node.js promise async-await

你如何处理没有解决的承诺?

例子:

class Utils {
    static async thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(number: number) {
        return new Promise((resolve, reject) => {
            if(number === 2) {
                resolve('ok')
            }
        })
    }
}

console.log(await Utils.thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(2))
// this will print "ok" because 2 is passed and the promise is resolved

console.log(await Utils.thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(5))
// this will crash the program silently 
Run Code Online (Sandbox Code Playgroud)

uncaughtExceptionunhandledRejection返回任何结果时,许是没有得到解决。try/catch在 await 周围添加一个不起作用(没有错误)。最后,唯一有效的是使用Promise.then而不是await.

问题是代码库充满了async/await有时会解决的承诺(取决于条件)

问题:是否可以添加打字稿标志来检测丢失的解析/拒绝?或者也许是一种自动转换所有async/await使用的方法Promise.then

使用调试器时,程序在 Promise 之后停止,很难找到哪个函数/promise 丢失了 resolve/reject。

重写所有async/await要使用的调用Promise.then是我最后的手段。

jfr*_*d00 9

如果您的承诺偶尔无法解决或拒绝,并且这不是他们应该工作的方式(通常不是),那么您只需要解决这个问题。真的没有解决方法。正确的修复方法是深入到最低级别并修复代码,以便它每次都能可靠地解决或拒绝。


这不是正确的修复,但实现超时包装器可以帮助调试,为您提供一条日志消息,其中包含一些类似堆栈跟踪的超时承诺:

function rejectT(t) {
    // create potential error here for better opportunity at stack trace
    let e = new Error("Promise timed out");
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(e);
            reject(e);
        }, t);
    });
}

function timeout(p, t = 5000) {
    return Promise.race([p, rejectT(t)]);
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以包装任何承诺,而不是:

fn().then(...).catch(...)
Run Code Online (Sandbox Code Playgroud)

您可以使用:

timeout(fn()).then(...).catch(...);
Run Code Online (Sandbox Code Playgroud)

或者,如果您想设置自定义超时值:

timeout(fn(), 1000).then(...).catch(...);
Run Code Online (Sandbox Code Playgroud)

同样,这是调试代码以帮助找到需要修复的罪魁祸首并帮助测试修复,而不是捆绑您的代码。

重写所有 async/await 调用以使用 Promise.then 是我最后的手段。

我根本看不出这会有什么帮助。如果await永远不会完成,也不会promise.then()。他们在这方面完全相同。如果承诺永远不会解决或拒绝,那么.then()处理程序也永远不会被调用。

问题是代码库充斥着 async/await 和有时会解决的承诺(取决于条件)

除了有条不紊的代码审查之外,这里没有其他捷径,可以找到具有永远无法解析或拒绝的代码路径的可疑代码,然后构建单元测试来测试在各种条件下返回承诺的每个函数。

一种可能永远不会解析或拒绝的代码来源是一些 promise 反模式。其中一些是反模式的确切原因是因为它们很容易搞砸。以下是一些可能会激发您对可疑代码的敏感性的参考资料:

Promise 反模式

常见的 Promise 反模式以及如何避免它们

ES6 承诺:模式和反模式

  • 仅供参考:找到了一种使用异步挂钩检测未解析/拒绝的承诺的方法 https://nodejs.org/api/async_hooks.html - 我可以识别哪些请求产生未解决的承诺,然后修复它们。我使用 codemod 在等待调用周围添加挂钩,然后运行测试套件和看起来有问题的旧请求来查找哪些承诺被破坏。谢谢你! (2认同)