如何在Kotlin/JS中正确导入并使用JavaScript异步函数?解决调用后返回Promise而非预期字符串的问题
问题分析与解决方案
你遇到的问题核心在于Kotlin/JS 不会自动将 JavaScript 的 Promise 转换为协程的挂起函数返回值,即使你给外部函数标记了 suspend。JavaScript 的 async 函数本质上是返回一个 Promise,而 Kotlin 的 suspend 修饰符只是标记函数是协程挂起函数,并没有处理 Promise 到协程的自动适配。
错误原因拆解
你当前的外部函数声明:
external object FirebasePorts{ suspend fun signUp(email: String, password: String) : String }
这里的 suspend 对 Kotlin/JS 的外部函数来说没有特殊意义——JS 的 signUp 返回的是 Promise,Kotlin 无法直接将其解析为 String,所以你拿到的还是原始的 Promise 对象。
正确的解决步骤
1. 修正外部函数的返回类型
首先,将外部函数的返回类型改为 Kotlin/JS 对应的 Promise<String>,明确它返回的是一个异步 Promise:
@JsModule("@jlengrand/firebase-ports") @JsNonModule external object FirebasePorts { fun signUp(email: String, password: String): Promise<String> }
2. 在协程中使用 await() 解析 Promise
Kotlinx-coroutines-js 库提供了 await() 扩展函数,可以将 Promise 转换为协程的挂起调用,获取最终的返回值。确保你的项目已经引入了 kotlinx-coroutines-js 依赖,然后修改调用代码:
var user : String? by mutableStateOf(null) Button( attrs = { onClick { GlobalScope.launch { try { // 用 await() 等待 Promise 完成并获取结果 user = FirebasePorts.signUp(email, password).await() } catch (e: Exception) { // 处理 JS 函数中抛出的错误(比如注册失败) println("注册失败: $e") } } } }) { Text("Sign Up!") } TextArea(value = user.toString())
3. 可选:包装为 Suspend 函数(更优雅的调用)
如果你希望调用时更像 Kotlin 原生的挂起函数,可以自己封装一层:
// 给 FirebasePorts 添加扩展的 suspend 函数 suspend fun FirebasePorts.signUpSuspend(email: String, password: String): String { return signUp(email, password).await() }
之后调用就可以直接用:
user = FirebasePorts.signUpSuspend(email, password)
额外注意点
- 错误处理:你的 JS 函数里有 try/catch,但如果
createUserWithEmailAndPassword失败,Promise 会被 reject,此时 Kotlin 调用await()会抛出异常,所以一定要在协程里添加 try/catch 处理错误。 - 依赖检查:确保
build.gradle.kts中包含 kotlinx-coroutines-js 依赖:implementation("org.jetbrains.kotlinx:kotlinx-coroutines-js:1.7.3")
内容的提问来源于stack exchange,提问作者jlengrand
相关产品推荐
相关产品推荐

