【问题标题】:Using runBlocking in Kotlin Coroutines when targeting JavaScript?以 JavaScript 为目标时在 Kotlin 协程中使用 runBlocking?
【发布时间】:2018-09-18 19:16:51
【问题描述】:

有没有办法编写下面的 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 时,代码可以编译并正常工作。 由于不存在函数 runBlocking,在针对 JavaScript 时会发出编译错误

【问题讨论】:

    标签: kotlin kotlin-coroutines kotlin-js


    【解决方案1】:

    你的主要问题是你没有要求你真正需要的东西。您编写的代码启动一个协程,暂停它,然后阻塞直到它完成。这完全等同于根本没有协程,只是发出阻塞的网络请求,这是你不可能期望 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,这段代码将无法编译
    • 另外,我试图避免在“请求”方法的签名中添加“挂起”,因为这意味着调用站点必须包含在协程中
    • GlobalScopekotlinx.coroutines.experimental 中,所以它必须在任何平台上都可用,但我不知道它是否是 JS 上的最佳选择。你不能避免suspend 和启动协程,因为这是它的工作原理。
    • 啊,一个重要提示:我的代码是针对最近发布的kotlinx-coroutines-experimental0.26 版本编写的。它弃用了几个关键机制,例如没有接收器的全局 launch
    猜你喜欢
    • 2019-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-17
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多