Какой идиоматический способ создания API в Kotlin с асинхронными операциями? - PullRequest
2 голосов
/ 10 июня 2019

При создании API в Kotlin, каков идиоматический способ обработки асинхронных действий?

Мы могли бы создать apis, который требует обычных блокирующих вызовов, заставляя код приложения использовать что-то вроде 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)
}

Есть ли консенсус или официальная позиция в отношении того, что нам следует делать?

1 Ответ

0 голосов
/ 10 июня 2019

Как упоминается в комментарии @ 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.

...