admin管理员组文章数量:1435859
I'm executing a JavaScript SDK from within a JSContext
, I can't get values out of any of the SDK's asynchronous functions however. I can get a JavaScript promise out of the JSContext
, but I can't figure out how to resolve it. I have tried many ways of getting the value from the Promise, but every one has failed.
If I try something like the following I get [object Promise]
back:
return self.jsContext.evaluateScript("new Promise(resolve => { setTimeout(300, () => resolve([1, 2, 3])) })")!
If I chain then
directly onto the JS I get [object Promise]
still:
return self.jsContext.evaluateScript("new Promise(resolve => { setTimeout(300, () => resolve([1, 2, 3])) }).then(val => val.json())")
If I try to invoke the method from Swift, I get still get [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!
If I declare a JS variable outside of the Promise, then pass the value to it from a Swift-invoked then
call, I get the original value set to it (as expected but worth a try):
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!
If I try and use top-level await
and resolve the Promise to a variable, then pull that variable out of the JSContext
, IU get a EXC_BAD_INSTRUCTION
error:
let jsPromise = self.jsContext.evaluateScript("let someVar = await new Promise(resolve => { setTimeout(300, () => resolve([1, 2, 3])) })")
return self.jsContext.evaluateScript("someVar")!
Thanks in advance, and sorry if I'm missing something, still very new to Swift.
I'm executing a JavaScript SDK from within a JSContext
, I can't get values out of any of the SDK's asynchronous functions however. I can get a JavaScript promise out of the JSContext
, but I can't figure out how to resolve it. I have tried many ways of getting the value from the Promise, but every one has failed.
If I try something like the following I get [object Promise]
back:
return self.jsContext.evaluateScript("new Promise(resolve => { setTimeout(300, () => resolve([1, 2, 3])) })")!
If I chain then
directly onto the JS I get [object Promise]
still:
return self.jsContext.evaluateScript("new Promise(resolve => { setTimeout(300, () => resolve([1, 2, 3])) }).then(val => val.json())")
If I try to invoke the method from Swift, I get still get [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!
If I declare a JS variable outside of the Promise, then pass the value to it from a Swift-invoked then
call, I get the original value set to it (as expected but worth a try):
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!
If I try and use top-level await
and resolve the Promise to a variable, then pull that variable out of the JSContext
, IU get a EXC_BAD_INSTRUCTION
error:
let jsPromise = self.jsContext.evaluateScript("let someVar = await new Promise(resolve => { setTimeout(300, () => resolve([1, 2, 3])) })")
return self.jsContext.evaluateScript("someVar")!
Thanks in advance, and sorry if I'm missing something, still very new to Swift.
Share Improve this question edited Mar 9, 2023 at 22:09 iUrii 13.9k2 gold badges39 silver badges62 bronze badges asked Sep 12, 2017 at 16:53 JmJJmJ 2,1283 gold badges31 silver badges53 bronze badges 1- What do you see in the object if you debug it with a breakpoint? – Jonas Commented Sep 16, 2017 at 18:06
2 Answers
Reset to default 4 +50There are issues while mocking the Promise work flow inside JSContext. The functions like setTimout,setInterval etc. are not available in JSContext.
However, you can call Swift code from Javascript by passing block into the JSContext. Here's a code snippet, that shows how you can find out errors in 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
To get resolved values (and rejected errors) from asynchronous javascript code you should operate with javascript's Promise
and its then
method:
Promise.prototype.then()
then(onFulfilled)
then(onFulfilled, onRejected)
then(
(value) => { /* fulfilment handler */ },
(reason) => { /* rejection handler */ },
)
We can call then
with the fulfilment handler which provides a resolved value from above, so let's implement that:
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)])
This approach works for async
functions as well because they operate with Promise
under the hood, for instance:
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)])
本文标签: javascriptGet value from JS Promiseasync function from within a JSContextStack Overflow
版权声明:本文标题:javascript - Get value from JS Promiseasync function from within a JSContext - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745638045a2667681.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论