我正在尝试编写一个Kotlin函数来执行HTTP请求,然后将结果返回给JavaScript。
因为使用IR编译器时,我无法使用JavaScript中的挂起函数,所以我尝试使用回调函数来代替。
然而,当从协程调用时,回调永远不会执行。
下面是我正在做的一个小例子:
private val _httpClient = HttpClient(JsClient()) {
install(ContentNegotiation) { json() }
defaultRequest { url(settings.baseUrl) }
}
fun requestJwtVcJsonCredential(
request: JSJwtVcJsonVerifiableCredentialRequest,
callback: (JSDeferredJsonCredentialResponse?, JSJwtVcJsonVerifiableCredentialResponse?, Any?) -> Unit
) {
CoroutineScope(_httpClient.coroutineContext).launch {
// call suspend function
val response = requestCredential(convert(request))
// this never runs, even though the coroutine does run successfully
println("Coroutine received: $response")
callback(response.first, response.second, response.third)
}
}
我注意到this question在Android中也有类似的问题,但建议的修复不适用于JavaScript......具体来说,使用Channel
对我的情况没有帮助,因为我没有一个协程来接收,并试图启动一个新的协程来从通道接收,然后从该协程调用回调,也不起作用(根本问题似乎是我不能从任何协程调用回调函数)。
解决这个问题的最好方法是什么?假设我需要调用的函数是一个suspend函数(HTTP客户端函数),我不能改变它,但是我可以改变它周围的一切,使它从一个非suspend函数工作(因为这是KotlinJS的一个限制)。
1条答案
按热度按时间pbpqsu0x1#
根本问题是suspend函数实际上失败了,但似乎没有默认的异常处理程序,因此异常没有记录在任何地方,导致函数静默失败,使回调看起来像是被调用但没有执行。
但是,我认为值得一提的是,KotlinJS支持
Promise<T>
,因此向JS公开suspend函数的更好方法是实际编写一个“适配器”函数,该函数返回Promise
。CouroutineScope
上有一个promise
extension function可用于此目的。例如,如果你有一个Kotlin函数:
要在JavaScript中公开它,可以使用如下适配器函数:
这避免了引入回调函数的需要。