You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Swift异步函数暂停直至JavaScriptCore回调返回结果

Swift 桥接 JavaScriptCore Promise 异步调用方案

核心实现基于Swift Concurrency提供的withCheckedThrowingContinuation,桥接JS Promise的resolve/reject回调,实现和原生async/await完全一致的调用体验,适配Vapor的异步路由逻辑。

核心实现逻辑

JS异步函数返回的Promise对象本身支持挂载成功/失败回调,你只需要把Swift侧Continuation的恢复方法封装成JS可识别的block,传入Promise的then/catch回调即可:

  • Promise被resolve时,触发成功回调,将结果传回Swift恢复异步执行
  • Promise被reject时,触发失败回调,将错误抛回Swift异步流程

可复用封装代码

首先定义通用的JS异步调用桥接方法:

import JavaScriptCore

enum JSPromiseBridgeError: Error {
    case invalidFunctionReturn
    case runtimeError(String)
}

/// 桥接JS异步函数,支持直接await获取JS Promise执行结果
/// - Parameters:
///   - jsFunction: JS侧的异步函数对象
///   - arguments: 调用JS函数需要传入的参数列表
/// - Returns: JS Promise resolve后返回的结果值
func callJSAsync(_ jsFunction: JSValue, arguments: [Any] = []) async throws -> JSValue {
    // 调用JS函数,拿到返回的Promise实例
    guard let promise = jsFunction.call(withArguments: arguments), promise.isObject else {
        throw JSPromiseBridgeError.invalidFunctionReturn
    }

    return try await withCheckedThrowingContinuation { continuation in
        // 封装成功回调:Promise resolve时触发
        let onFulfilled: @convention(block) (JSValue) -> Void = { result in
            continuation.resume(returning: result)
        }
        // 封装失败回调:Promise reject时触发
        let onRejected: @convention(block) (JSValue) -> Void = { error in
            let message = error.toString() ?? "未知JS运行时错误"
            continuation.resume(throwing: JSPromiseBridgeError.runtimeError(message))
        }
        // 给Promise挂载回调,注意block需要通过unsafeBitCast转换为JS可识别的对象
        promise.invokeMethod("then", withArguments: [unsafeBitCast(onFulfilled, to: AnyObject.self)])?
            .invokeMethod("catch", withArguments: [unsafeBitCast(onRejected, to: AnyObject.self)])
    }
}

业务侧使用示例

替换你原来的myAsyncFunction实现即可,不需要修改Vapor侧的路由注册逻辑:

func myAsyncFunction() async -> Bool {
    let jsContext = JSEngine().evaluateScript(myJSCode)
    guard let targetJSFunc = jsContext.objectForKeyedSubscript("myAsyncJSFunction") else {
        return false
    }
    
    do {
        let jsResult = try await callJSAsync(targetJSFunc, arguments: [data])
        // 根据业务需要把JSValue转为对应类型,这里示例转Bool
        return jsResult.toBool()
    } catch {
        // 按需处理错误,例如打印日志、返回默认值
        print("JS异步执行失败: \(error)")
        return false
    }
}

注意事项

  • 所有传入JSContext的Swift闭包必须添加@convention(block)标记,否则JavaScriptCore无法正确识别调用,会出现回调不触发、内存崩溃问题
  • 确保Continuation的resume方法只会被调用一次,上述实现中Promise的then和catch天然互斥,不会出现多次resume的问题
  • 如果你的JS逻辑采用回调风格而非返回Promise,只需要把封装好的onFulfilled、onRejected作为参数直接传给JS函数即可,桥接逻辑完全一致
  • 该实现完全兼容Vapor的异步事件循环模型,等待JS执行的过程中不会阻塞服务端其他请求处理

内容的提问来源于stack exchange,提问作者mrtksn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 09:27:09