kotlinx.coroutines
kotlinx.coroutines copied to clipboard
Stabilize Deferred.getCompleted and related
At the moment, Deferred.getCompleted() and Deferred.getCompletionExceptionOrNull() are experimental and marked with @ExperimentalCoroutinesApi.
The functions above are useful for polling and accessing the deferred result from a non-suspend context where it's impossible to wait for the completion. The related function invokeOnCompletion {} is usually used with these experimental function to access the computation result after its completion. And of course, the callback handler is a regular non-suspend lambda. So without using experimental functions, the only solution is to launch a coroutine in the handler or trigger some existing coroutine (via channel or something). This is too much boilerplate. Fortunately, we have the experimental function providing a way to access the computation result just in place.
The typical usages I've faced are the following.
Generally using the pair looks like:
deferred.invokeOnCompletion { cause ->
when (cause) {
null -> deferred.getCompleted()
else -> ....
}
}
Handle only if successful:
deferred.invokeOnCompletion { cause ->
if (cause != null) {
handle(deferred.getCompleted())
}
}
getCompletedOrNull:
deferred.invokeOnCompletion { cause ->
handle(when (cause) {
null -> deferred.getCompleted()
else -> null
})
}
Ensure resource cleanup:
deferred.invokeOnCompletion { cause ->
if (cause != null) {
deferred.getCompleted().close()
}
}
Bridge two deferred:
deferred.invokeOnCompletion { cause ->
when (cause) {
null -> publicDeferred.complete(deferred.getCompleted())
else -> publicDeferred.completeExceptionally(cause)
}
}
Tracking instant async job status (e.g. in web UI without websockets and instant notification):
onPageLoad {
when {
!deferred.isCompleted -> putInProgressLabel()
deferred.isCancelled -> putCancelledLabel()
deferred.getCompletionException() != null -> putFailedLabel()
else -> putSuccessLabel(deferred.getCompled())
}
The alternative API could be
fun Deferred<T>.getCompletionResult(): Result<T>
fun Deferred<T>.invokeOnCompleteionWithResult(handler: (Result<T>) -> Unit)