Search code examples
javascriptgoasynchronouspromisewebassembly

await js async function (promise) inside a go function


I am looking to integrate indexdb in a wasm based app. How do you "await" in a go function a promise from a js function. Here is the example

    async getItem(key) {
        try{
            const out = await database.getItem(key);
            return out;
        }catch(err){
            return null;
        }
    }

and in go

func Get(key string)[]byte{

    found :=  js.Global().Get("Store").Call('getItem', key )
    // await for found
    // convert js.Value to to []byte
    return nil

}

Async callbacks are fine too.

LE: one bad solution would be to create a go routine with an infinite loop waiting until a DOM variable exists like global.solution+ID to be set. But I believe this is a bad solution


Solution

  • You can use the then method from the Promise object to wait for the result, something like this:

    package main
    
    import (
        "fmt"
        "syscall/js"
    )
    
    func main() {
        wait := make(chan interface{})
        js.Global().Call("sayHello", 5000).Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
            fmt.Println(args[0])
            wait <- nil
            return nil
        }))
        <-wait
        fmt.Println("we're done here")
    }
    

    Notice that we are using a channel to actually wait in the Go code. We need to do that because the Go program must still be running while receiving the callback from Javascript.

    The index.html file:

    <html>
        <head>
            <meta charset="utf-8"/>
            <script src="wasm_exec.js"></script>
            <script>
                const go = new Go();
                WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
                    go.run(result.instance);
                });
    
                function sayHello(time) {
                    return new Promise(resolve => {
                        console.log('waiting %dms and resolving', time)
                        setTimeout(() => resolve('hola!'), time)
                    })
                }
            </script>
        </head>
        <body></body>
    </html>