2

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

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
algorithmitcus
  • 595
  • 1
  • 5
  • 7

2 Answers2

1

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>
Gustavo Kawamoto
  • 2,665
  • 18
  • 27
  • You might want to see [this answer](https://stackoverflow.com/questions/68426700/how-to-wait-a-js-async-function-from-golang-wasm/68427221#comment120939975_68427221) @algorithmitcus – Gustavo Kawamoto Jul 23 '21 at 08:53
1

Promise, real example (go.1.18):

type DevicesData struct {
    DeviceId string
    GroupId string
    Kind string
    Label string
}

list = make([]DevicesData, 0)
end := make(chan struct{})

// golang has a bug:
// enumerateDevices() returns an array, but, go returns an object.
forEach := js.FuncOf(func(_ js.Value, args []js.Value) any {
    data := DevicesData{
        DeviceId: args[0].Get("deviceId").String(),
        GroupId:  args[0].Get("groupId").String(),
        Kind:     args[0].Get("kind").String(),
        Label:    args[0].Get("label").String(),
    }
    list = append(list, data)

    // aways return nil
    return nil
})

// promise success function
var success = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
    args[0].Call("forEach", forEach)
    end <- struct{}{}

    // aways return nil
    return nil
})

var failure = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
    err = errors.New(args[0].Get("message").String())

    // aways return nil
    return nil
})

js.Global().Get("navigator").Get("mediaDevices").Call("enumerateDevices").Call("then", success, failure)

// wait async call
<-end
Helmut Kemper
  • 662
  • 1
  • 6
  • 15