I would like to call an async JS function from within Swift using JavaScriptCore. However, when the JS function is asynchronous, how do I force the Swift function call to wait until the async javascript function behind it has completed running?
Currently all this call returns is
[object Promise]
This is my current attempt
import SwiftUI
import JavaScriptCore
class Cube {
func getNfts(pubKey: String) async -> String? {
let jsCode =
"""
async function lookupNfts(pubKey, callback) {
try {
const config = {
apiKey: "API KEY",
network: Network.MATIC_MUMBAI,
};
const alchemy = new alc.Alchemy(config);
const { nfts } = await fetch(alchemy.nft.getNftsForOwner(pubKey));
callback(nfts.ownedNfts)
return nfts.ownedNfts
//swiftCallback(nfts);
} catch (error) {
console.log(error);
}
};
"""
let context = JSContext()
context!.evaluateScript(jsCode)
guard let alc = Bundle.main.path(forResource: "alchemy", ofType: "js") else {
print("Unable to read resource file")
return nil
}
let functionInJS = context!.objectForKeyedSubscript("lookupNfts")
let _ = print(functionInJS)
let testBlock : @convention(block) (JSValue?) -> Void = { calledBackValue in
let _ = print("calledBackValue:", calledBackValue)
}
let callback = JSValue.init(object: testBlock, in: context)
let res = functionInJS!.call(withArguments: [pubKey, callback]).toString()
let _ = print(res)
return res
}
}
struct ContentView: View {
var myvar = "hello";
@State private var sourceCode = "Loading…"
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
//Cube().getNfts(pubKey: "wallet address")
Text(sourceCode ?? "No result")
})
}
.padding()
.task{
let mycube = Cube()
var res = "";
do {
let data = await mycube.getNfts(pubKey: "mypubkey") ?? "nothinghere"
sourceCode = String(data)
} catch {
sourceCode = "Failed to fetch site."
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
(absolute swift newcomer)
Javascript
asyncfunctions operates withPromiseunder the hood and you can invokethenmethod on your[object Promise]with fulfilment and rejection handlers so you don't need any additional callbacks to get a resolved values or rejected errors, e.g.:Based on this we can implement a generic swift
asyncfunction which waits for the Promise's handlers:How to use: