当针对JavaScript时,在Kotlin协程中使用runBlocking?

5
有没有一种方法可以编写下面的Kotlin代码,让它在JVM和JavaScript上编译并以相同的方式工作?
fun <A: Any> request(request: Any): A  = runBlocking {
    suspendCoroutine<A> { cont ->
        val subscriber = { response: A ->
                cont.resume(response)
        }
        sendAsync(request, subscriber)
    }
}


fun <Q : Any, A : Any> sendAsync(request: Q, handler: (A) -> Unit) {

    // request is sent to a remote service,
    // when the result is available it is passed to handler(... /* result */)

}

当编译目标为JVM时,该代码可以编译并正常运行。但是编译目标为JavaScript时会发出编译错误,原因是runBlocking函数不存在。

1个回答

3
你的主要问题在于你没有请求实际需要的东西。你编写的代码启动了一个协程,暂停它,然后阻塞直到它完成。这与根本没有协程并只进行阻塞网络请求完全相同,这是你不可能期望JavaScript允许的事情。
实际上,你需要做的是回到request()的调用站点,并将其包装在launch中:
GlobalScope.launch(Dispatchers.Default) {
    val result: A = request(...)
    // work with the result
}

有了这个设置,你可以重写你的请求函数为:

suspend fun <A: Any> request(request: Any): A = suspendCancellableCoroutine {
    sendAsync(request, it::resume)
}

我认为GlobalScope::launch不是Kotlin js协程库的一部分 - 如果目标是JS,这段代码将无法编译。 - auser
1
此外,我试图避免将"suspend"添加到"request"方法的签名中,因为这意味着调用站点必须包装在协程中。 - auser
GlobalScopekotlinx.coroutines.experimental 中,因此它必须在任何平台上都可用,但我不知道它是否是 JS 上的最佳选择。您无法避免使用 suspend 和启动协程,因为这就是其工作原理的本质。 - Marko Topolnik
啊,一个重要的注意事项:我的代码是针对最近发布的kotlinx-coroutines-experimental版本0.26编写的。它弃用了几个关键机制,比如没有接收器的全局launch - Marko Topolnik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接