使用Kovenant,我有时会使用Promise.of(value)
函数创建一个我希望包装为promise的同步结果。但有时会这样称呼:
Promise.of(callSomeCalculation()) <-- throws exception sometimes
.then { ... }
.then { ... }
.fail { ex -> log.error(ex) } <-- exception is not logged
此代码丢失了第一个承诺期间发生的异常。他们去哪儿了?它们永远不会被记录。有时他们只是用未处理的异常来崩溃我的应用程序。为什么承诺没有抓住他们所有人?
注意: 此问题是由作者(Self-Answered Questions)故意编写和回答的,因此可以在SO中分享有趣问题的解决方案。
答案 0 :(得分:2)
问题是你在承诺链之外泄露异常。想象一下这段代码:
fun makeMyPromise(): Promise<Int, Exception> {
val result: Int = callSomeCalculation() // <--- exception occurs here
val deferred = deferred<Int, Exception>()
deferred.resolve(result)
return deferred.promise
}
这基本上是您的代码在第一行中所做的事情。如果抛出异常,则该方法将以异常退出,并且永远不会调用deferred.reject
。将代码更改为:
fun makeMyPromise(): Promise<Int, Exception> {
val deferred = deferred<Int, Exception>()
try {
val result: Int = callSomeCalculation() // <--- exception occurs here
deferred.resolve(result)
} catch (ex: Exception) {
deferred.reject(ex)
}
return deferred.promise
}
会更正确并抓住你的例外。并且它确保没有任何东西可以从承诺链泄漏。
回到原始代码,callSomeCalculation()
正在调用Promise.of()
方法之前发生,并且无法提供此类保护。它发生在Kovenant有一个想法,你甚至创造了一个承诺。因此,您需要一个新的Promise.of(lambda)
方法,该方法接受可以完全防止此类泄漏的代码块。
这是一个新的Promise.of(lambda)
扩展功能:
fun <V> Promise.Companion.of(codeBlock: () -> V): Promise<V, Exception> {
val deferred = deferred<V, Exception>()
try {
deferred.resolve(codeBlock())
}
catch (ex: Exception) {
deferred.reject(ex)
}
return deferred.promise
}
将用作:
Promise.of { callSomeCalculation() } <-- sometimes throws exception
.then { ... }
.then { ... }
.fail { ex -> log.error(ex) } <-- exception ALWAYS logged!
请注意,括号()
已更改为{}
括号,因为现在代码块已传递到Promise.of
方法并包含异常处理,以防止任何泄漏。现在,您将在后面的fail { .. }
块中看到您的异常。