在Kotlin中创建API时,处理异步操作的惯用方式是什么?
我们可以创建需要常规阻塞调用的api,从而迫使应用程序代码使用类似runBlocking
之类的东西。
////
//// Plain functions
////
// library code
fun registerHandler(block: (it: Foo) -> String) {
// save a reference to call when an action happens later
}
// application code
registerHandler {
runBlocking {
handleItSuspend(it)
}
}
我们可以更多地使用suspend
,这对应用程序代码来说看起来更好,但是要求我们从暂停函数或协程上下文执行回调,这可能给我们带来麻烦,也可能不会带来麻烦。
////
//// Suspend functions
////
// library code
fun registerHandler(block: suspend (it: Foo) -> String) {
// save a reference to call when an action happens later
}
// application code
registerHandler {
handleItSuspend(it)
}
或者我们可以采用返回延迟结果的函数
////
//// Deferred functions
////
// library code
// This handler can be called from anywhere without needing suspend.
fun registerHandler(block: (it: Foo) -> Deferred<String>) {
// save a reference to call when an action happens later
}
// application code
registerHandler {
// Function that isn't suspend but returns a deferred
handleItAsync(it)
}
对于我们应该做的事情是否有共识或正式立场?
答案 0 :(得分:0)
正如@ msrd0在注释中提到的那样,您可以轻松地在第二种方法和第三种方法的参数之间进行转换,因此它们是等效的:
val block1: suspend (Foo) -> String = ...
val block2: (Foo) -> Deferred<String> = { x -> async { block1(x) } }
val block3: suspend (Foo) -> String = { x -> block2(x).await() }
但是我希望大多数对Deferred
版本的调用看起来像
registerHandler { foo -> async { doSomethingSuspend(foo) } }
在这种情况下,suspend
版本更易于使用,它将只是
registerHandler { foo -> doSomethingSuspend(foo) }
当然,您的代码库可能已经足够普遍使用Deferred
了,以致这种假设不成立。
要求我们从挂起函数或协程上下文执行回调,这可能会给我们带来麻烦,也可能不会给我们带来麻烦。
我认为这不太方便,因为它只是async
内部的一个简单的registerHandler
(或其他协程生成器)调用。
或者您的意思是说registerHandler
需要在那里打电话吗?仅当它被本身声明为suspend
时,这种情况才会成立。