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

Posted

技术标签:

【中文标题】从 JSContext 中获取 JS Promise/async 函数的值【英文标题】:Get value from JS Promise/async function from within a JSContext 【发布时间】:2017-09-12 16:53:35 【问题描述】:

我正在从 JSContext 中执行 javascript SDK,但是我无法从任何 SDK 的异步函数中获取值。我可以从JSContext 中得到一个 JavaScript 承诺,但我不知道如何解决它。我尝试了很多从 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")!

在此先感谢,如果我遗漏了一些东西,我很抱歉,这对 Swift 来说还是很新的。

【问题讨论】:

如果你用断点调试它,你会在对象中看到什么? 【参考方案1】:

在 JSContext 中模拟 Promise 工作流时存在问题。 JSContext中没有setTimout、setInterval等函数。

但是,您可以通过将块传递给 JSContext 来从 Javascript 调用 Swift 代码。这是一个代码 sn-p,它显示了如何在 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

【讨论】:

以上是关于从 JSContext 中获取 JS Promise/async 函数的值的主要内容,如果未能解决你的问题,请参考以下文章

iOS js 使用与JSContext

无法在 JavaScriptCore JSContext 中运行 proj4.js

jsContext全局函数调用与对象函数调用evaluateScript

iOS JS 交互之利用系统JSContext实现 JS调用oc方法

iOS JS 交互之利用系统JSContext实现 JS调用oc方法

获取字符串的值类型(JSContext evaluateScript)