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.
There 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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With