如何处理未解决的Promise:await/async

huangapple go评论85阅读模式
英文:

await/async how to handle unresolved promises

问题

如何处理未解决的承诺?

示例:

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

console.log(await Utils.thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(2))
// 这将打印 "ok" 因为传递了 2 并且承诺已解决

console.log(await Utils.thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(5))
// 这将导致程序悄悄崩溃

当承诺未解决时,uncaughtExceptionunhandledRejection 不返回任何内容。在 await 周围添加 try/catch 不起作用(没有错误)。最后,唯一有效的方法是使用 Promise.then 而不是 await

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

问题:是否有 TypeScript 标志可以添加以检测缺少的 resolve/reject?或者是否有一种自动转译所有的 async/await 以使用 Promise.then 的方法?

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

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

英文:

How do you handle promises that do not resolve?

Example:

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 

uncaughtException and unhandledRejection return nothing when the promise is unresolved. Adding a try/catch around the await doesn't work (no errors). Finally, the only thing that works is using Promise.then instead of await.

Problem is the code base is riddled with async/await and Promises that sometimes resolve (depending on conditions)

Question: Is there a typescript flag I can add to detect a missing resolve/reject? or maybe an automated way to transpile all the async/await to use Promise.then?

When using a debugger, the program stops after the Promise and it is difficult to find which function/promise has a missing resolve/reject.

Rewriting all the async/await calls to use Promise.then is my last resort.

答案1

得分: 10

如果您的承诺有时不会解决或拒绝,而这不是它们应该工作的方式(通常情况下是这样),那么您只需修复它。真正的修复方法是深入到最低层级并修复代码,以确保它每次都可靠地解决或拒绝。

这不是正确的修复方法,但实现一个超时包装器可以帮助调试,为超时的承诺提供带有某种堆栈跟踪的日志消息:

function rejectT(t) {
    // 在这里创建潜在的错误以获得更好的堆栈跟踪机会
    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)]);
}

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

fn().then(...).catch(...);

您可以使用:

timeout(fn()).then(...).catch(...);

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

timeout(fn(), 1000).then(...).catch(...);

再次强调,这是调试代码,用于帮助找到需要修复的问题,并帮助测试修复,而不是为您的代码打补丁。

重新编写所有的异步/等待调用以使用Promise.then是我的最后手段。

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

问题是代码库中充斥着有时会解决(取决于条件)的异步/等待和承诺

除了方法ical代码审查以查找可能永远不会解决或拒绝的代码路径,然后构建单元测试来测试返回承诺的每个函数的方法之外,这里没有捷径。

永远不会解决或拒绝的代码的一个可能的来源是一些承诺反模式。一些反模式之所以是反模式,是因为它们很容易出错。以下是一些可能会引发您对可疑代码敏感性的参考资料:

承诺反模式

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

ES6承诺:模式和反模式

英文:

If you have promises that occasionally don't resolve or reject and that's not the way they are supposed to work (which it usually isn't), then you just have to fix that. There really is no work-around. The proper fix is to get down to the lowest level and fix the code so it reliably resolves or rejects every time.


This is not the proper fix, but implementing a timeout wrapper could help with debugging giving you a log message with some semblance of a stack trace for a timed out promise:

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)]);
}

You can then wrap any promise such that instead of:

fn().then(...).catch(...)

You can use:

timeout(fn()).then(...).catch(...);

Or, if you want to set a custom timeout value:

timeout(fn(), 1000).then(...).catch(...);

Again, this is debugging code to help find the culprits that need fixing and to help test fixes, not to bandaid your code.

> Rewriting all the async/await calls to use Promise.then is my last resort.

I don't see how this is going to help at all. If await never finishes, neither will promise.then(). They are exactly the same in that regard. If the promise never resolves or rejects, then the .then() handler will never get called either.

> Problem is the code base is riddled with async/await and Promises that sometimes resolve (depending on conditions)

There's no shortcut here other than methodical code review to find suspect code that has code paths that may never resolve or reject and then building unit tests to test every function that returns a promise in a variety of conditions.

One likely source of code that never resolves or rejects are some of the promise anti-patterns. The precise reason some of them are anti-patterns is because they can be very easy to mess up. Here are a few references that might spike your sensitivity to suspect code:

Promise Anti-Patterns

Common Promise Anti-Patterns and How to Avoid Them

ES6 Promises: Patterns and Anti-Patterns

答案2

得分: 0

    async function thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(number) {
      return new Promise((resolve, reject) => {
        if (number === 2) {
          resolve('ok')
        } else {
          reject('error:' + number)
        }
      })
    }
    (async() => {
      try {
        console.log(await thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(2))
        // this will print "ok" because 2 is passed and the promise is resolved
      } catch (e) {
        console.error(e);
      }
      try {
        console.log(await thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(5))
        // this will crash the program silently
      } catch (e) {
        console.error(e);
      }
    })()
英文:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

async function thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(number) {
  return new Promise((resolve, reject) =&gt; {
    if (number === 2) {
      resolve(&#39;ok&#39;)
    } else {
      reject(&#39;error:&#39; + number)
    }
  })
}
(async() =&gt; {
  try {
    console.log(await thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(2))
    // this will print &quot;ok&quot; because 2 is passed and the promise is resolved
  } catch (e) {
    console.error(e);
  }
  try {
    console.log(await thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(5))
    // this will crash the program silently
  } catch (e) {
    console.error(e);
  }
})()

<!-- end snippet -->

huangapple
  • 本文由 发表于 2020年1月3日 13:21:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/59573554.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定