【问题标题】:How To await a function call?如何等待函数调用?
【发布时间】:2019-11-23 14:51:44
【问题描述】:

所以我发生了一些异步操作,我可以创建一些lambada,调用一个函数并将该值传递给它们。但我想要的不是将操作的结果作为参数,我想返回它们。

例如,我有一个带有一些侦听器的 A 类,如果有结果,所有侦听器都会收到通知。所以基本上 asyncFunction 应该返回一个结果,否则会被挂起。

object A {
    val listeners = mutableListOf<(Int) -> Unit>()

    fun onResult(value: Int) {
        listeners.forEach { it(value) }
    }
}

fun asyncFunction(): Deferred<Int> {
    return async {
        A.listeners.add({ result ->

        })

        return result
    }
}

我现在在想的是(也许我完全走错了路),是有一个像 Def​​erred 这样的东西,我可以将结果发送到它并返回。有没有类似的东西?我可以自己实现 Defered 吗?

class A {
    private val awaiter: ??? // can this be a Deferred ?

    fun onResult(result: Int) {
        awaiter.putResult(result)
    }

    fun awaitResult(): Int  {
        return awaiter.await()
    }
}

val a = A()

launch {
    val result = a.awaitResult()
}

launch {
    a.onResult(42)
}

所以我确实知道使用回调可以处理这个问题,但这样会更干净、更容易。

我希望我只是缺少一个漂亮而干净的解决方案。

【问题讨论】:

  • 协程是为了让你不需要回调,我建议你使用通道或流而不是回调。
  • 我在考虑这个,但这意味着我在 asyncFunction() 中创建了一个通道,将它传递给 A 类,然后将值放入通道中,我只收到通道的第一个值。如果您知道我的意思,我想要一个仅用于一个对象的频道。或者我应该以这种方式使用频道,如果可能的话?
  • 您创建一个生产者,然后创建所需的消费者数量和位置。

标签: kotlin kotlin-coroutines


【解决方案1】:

您的asyncFunction 实际上应该是一个可挂起的函数:

suspend fun suspendFunction(): Int =
    suspendCoroutine { cont -> A.listeners.add { cont.resume(it) } }

请注意,它会返回 Int 结果并暂停,直到可用为止。

但是,这只是解决您当前问题的方法。它仍然会在许多方面出现故障:

  • 侦听器的目的在它得到第一个结果后立即执行,但它永远留在侦听器列表中,导致内存泄漏
  • 如果结果在您调用suspendFunction 之前到达,它将错过它并挂起。

您可以继续手动改进它(这是一种很好的学习方式)或切换到标准库提供的可靠解决方案。图书馆解决方案是CompletableDeferred

object A {
    val result = CompletableDeferred<Int>()

    fun provideResult(r: Int) {
        result.complete(r)
    }
}

suspend fun suspendFunction(): Int = A.result.await()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-22
    • 2021-06-03
    • 2021-03-29
    • 2018-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-31
    相关资源
    最近更新 更多