Home > Net >  Run Go-WebAssembly before onmessage event in a Web Worker
Run Go-WebAssembly before onmessage event in a Web Worker

Time:09-14

I'm trying to include a Go-WebAssembly function inside a JavaScript Web Worker, and the problem is that the event onmessage from the worker runs before the WebAssembly loads so everytime I call the WebAssembly function I got an error: "yourFunction is not defined". I hope you can help me figuring out how to solve this problem or you can give me ideas how to implement this. Thanks !

A simplified version of my code:

main.go

package main

import (
    "fmt"
    "log"
    "syscall/js"
)

func myGoFunction(this js.Value, i []js.Value) interface{} {
    //Do some hard work
    fmt.Println(i[0])
    return true
}

func main() {
    js.Global().Set("myGoFunction", js.FuncOf(myGoFunction))
    <-make(chan bool)
}

main.js

const doSomething = () => {
if (myArray.length > 0)
    worker.postMessage({ value: myArray.shift() })
}

const init = () => {
    if (worker) worker.terminate()
    worker = new Worker('worker.js')
    worker.postMessage({ a: A, b: B, bool: true })
    worker.onmessage = doSomething
}

init()

worker.js

importScripts('wasm_exec.js');

const go = new Go();
WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
    go.run(result.instance);
});

onmessage = (e) => {

    const {settings} = e.data
    
    if (settings) {
       //set some values
    } else {

      for (let i= 0; i < 1000000; i  )
        someArray[i] = calculate(i)

        postMessage({someArray})
    }
}

const calculate = (i) => {
   //Do more

   //Here is where I call the go function
   myGoFunction(i)
}

Something I did to see if the myGoFunction is loading, is to put the WebAssembly.instantiateStreaming into a promise then call the onmessage but of course this will load the WebAssembly.instantiateStreaming millions of times and the job is done but extremely slow. Or maybe I implemented the promises the wrong way. I don't know, please help. :D

CodePudding user response:

You can store the promise returned from WebAssembly.instantiateStreaming() and await it in your onmessage handler:

const waInit = WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
  go.run(result.instance);
});
onmessage = async (e) => {
  await waInit; // now WA is ready
  const {settings} = e.data
  // The rest of your handler
  • Related