javascript 从JSContext中的JS Promise/async函数获取值

tf7tbtn2  于 2023-03-11  发布在  Java
关注(0)|答案(2)|浏览(186)

我正在JSContext中执行JavaScript SDK,但是我无法从SDK的任何异步函数中获取值。我可以从JSContext中获取JavaScript promise,但是我不知道如何解决它。我尝试了许多从Promise获取值的方法,但是每一种都失败了。
如果我尝试类似下面的代码,我会返回[object Promise]

return self.jsContext.evaluateScript("new Promise(resolve => { setTimeout(300, () => resolve([1, 2, 3])) })")!

如果我把then直接链接到JS上,仍然得到[object Promise]

return self.jsContext.evaluateScript("new Promise(resolve => { setTimeout(300, () => resolve([1, 2, 3])) }).then(val => val.json())")

如果我尝试从Swift调用这个方法,仍然会得到[object Promise]

let jsPromise = self.jsContext.evaluateScript("new Promise(resolve => { setTimeout(300, () => resolve([1, 2, 3])) })")
let promiseResult = jsPromise?.invokeMethod("then", withArguments: ["val => { return val.json() }"])
return promiseResult!

如果我在Promise之外声明了一个JS变量,然后通过Swift调用的then调用将值传递给它,我得到了它的原始值集(正如预期的那样,但值得一试):

self.jsContext.evaluateScript("let tempVar = 'Nothing has happened yet!'")
let jsPromise = self.jsContext.evaluateScript("new Promise(resolve => { setTimeout(300, () => resolve([1, 2, 3])) })")
let promiseResult = jsPromise?.invokeMethod("then", withArguments: ["val => { tempVar = val }"])
let tempVar = self.jsContext.evaluateScript("tempVar")
return tempVar!

如果我尝试使用顶级await并将Promise解析为变量,然后将该变量从JSContext中取出,IU会得到EXC_BAD_INSTRUCTION错误:

let jsPromise = self.jsContext.evaluateScript("let someVar = await new Promise(resolve => { setTimeout(300, () => resolve([1, 2, 3])) })")
return self.jsContext.evaluateScript("someVar")!

提前感谢,如果我错过了什么,对不起,仍然是非常新的斯威夫特。

hjzp0vay

hjzp0vay1#

在JSContext中模拟Promise工作流时出现问题。setTimout、setInterval等函数在JSContext中不可用。
然而,你可以通过将block传递到JSContext来从Javascript调用Swift代码。下面是一个代码片段,它展示了你如何在JSContext中找到错误。

var logValue = "" {
    didSet {
        print(logValue)
    }
}
//block we can pass to JSContext as JS function
let showLogScript: @convention(block) (String) -> Void = { value in
    logValue = value
}
let jsContext = JSContext()

//set exceptionHandler block
jsContext?.exceptionHandler = {
    (ctx: JSContext!, value: JSValue!) in
    print(value)
}
//make showLog function available to JSContext
jsContext?.setObject(unsafeBitCast(showLogScript, to: AnyObject.self), forKeyedSubscript: "showLog" as (NSCopying & NSObjectProtocol))

jsContext!.evaluateScript("showLog('this is my first name')") //this works
jsContext!.evaluateScript("showLog(setTimeout.name)") //it has issue
dtcbnfnu

dtcbnfnu2#

要从异步javascript代码中获取解析值(和拒绝的错误),应该使用javascript的Promise及其then方法:

Promise.prototype.then()

then(onFulfilled)
then(onFulfilled, onRejected)

then(
  (value) => { /* fulfilment handler */ },
  (reason) => { /* rejection handler */ },
)

我们可以用实现处理程序调用then,它提供了上面解析的值,所以让我们实现它:

let script = """
new Promise(resolve => {
    setTimeout(() => resolve([1, 2, 3]), 300)
})
"""
let promise = context.evaluateScript(script)

let onFulfilled: @convention(block) (JSValue) -> Void = {
    print($0) // Prints: 1,2,3
}
promise?.invokeMethod("then", withArguments: [unsafeBitCast(onFulfilled, to: JSValue.self)])

这种方法也适用于async函数,因为它们在幕后使用Promise操作,例如:

let script = """
async function load() {
    return [1, 2, 3];
}
"""
context.evaluateScript(script)

let promise = context.evaluateScript("load()")

let onFulfilled: @convention(block) (JSValue) -> Void = {
    print($0) // Prints: 1,2,3
}
promise?.invokeMethod("then", withArguments: [unsafeBitCast(onFulfilled, to: JSValue.self)])

相关问题