Problems with syscall/js with Go and WebAssembly

Hi!

I’m currently looking into WebAssembly and figured Go would be more interesting then Rust, but I didn’t come very far before I hit a big wall.

It seems I for some reason is unable to use syscall/js. My first simple hello world example works fine, and I have other Go projects that run as well, so I’m quite sure my environment is ok. But as soon I try to work with the js-object it all breaks.

My HTML page looks like this:

<html>
    <head>
        <meta charset="utf-8">
        <title>Go WebAssembly Demo</title>
    </head>

    <body>
        <script src="wasm_exec.js"></script>
        <script>
		if (!WebAssembly.instantiateStreaming) { // polyfill
			WebAssembly.instantiateStreaming = async (resp, importObject) => {
				const source = await (await resp).arrayBuffer();
				return await WebAssembly.instantiate(source, importObject);
			};
		}

		const go = new Go();
		let mod, inst;

		WebAssembly.instantiateStreaming(fetch("lib.wasm"), go.importObject).then(async (result) => {
			mod = result.module;
			inst = result.instance;
			await go.run(inst)
		});
        </script>
    </body>
</html>

My Go code looks like this:

package main

import "syscall/js"

// import "syscall/js"

func add(i []js.Value) {
	js.Global().Set("output", js.ValueOf(i[0].Int()+i[1].Int()))
	println(js.ValueOf(i[0].Int() + i[1].Int()).String())
}

func subtract(i []js.Value) {
	js.Global().Set("output", js.ValueOf(i[0].Int()-i[1].Int()))
	println(js.ValueOf(i[0].Int() - i[1].Int()).String())
}

func registerCallbacks() {
	js.Global().Set("add", js.NewCallback(add))
	js.Global().Set("subtract", js.NewCallback(subtract))
}

func main() {
	c := make(chan struct{}, 0)

	println("WASM Go Initialized")

	registerCallbacks()
	<-c
}

I build this code with this command;

GOARCH=wasm GOOS=js go build -o lib.wasm main.go

The error I get in the browser when using syscall/js is:

Unhandled Promise Rejection: TypeError: this._inst.exports.getsp is not a function. (In 'this._inst.exports.getsp()', 'this._inst.exports.getsp' is undefined)

I don’t get any compile errors and go build produce a lib.wasm for me. All code that doesn’t include syscall/js works fine. What do I do wrong here?

Hi Jonas,

My recent post about WebAssembly has links to my code on GitHub for two working examples. That will show you how to get started.

It looks like you are using the TutorialEdge “calculator” example of WebAssembly. (https://tutorialedge.net/golang/go-webassembly-tutorial/) I and some others on the forum tried that, and it worked for us. (Except for a small problem.)

I can’t say for sure, but it looks like maybe there is something wrong with your JavaScript glue code. The way I handled it was to copy the file wasm_exec.js from $GOROOT/misc/wasm. There is also an HTML file there that shows how to include that and some more JavaScript glue code in your HTML page (which you show in your first listing). I used the HTML from the most recent Go distribution (1.11.2) with two modifications:

  1. change the name of the wasm file to lib.wasm in the WebAssembly.instantiateStreaming(fetch(<wasm_file>) ...) call.
  2. Remove this line:
    document.getElementById("runButton").disabled = false;

Anyway, that’s how I did it. I do not know if this is absolutely correct because as I’ve reported, I’m having problems with some OS/browser combinations. But it works almost all the time. That’s the best I have for now, and I’m waiting to see if I get more replies before asking on the Go mailing list, or submitting an issue report.

1 Like

Replacing the Wasm_exec.js as you pointed out did it for me. I guess the one I downloaded from the tutorial didn’t work, and I had no clue it actually already was included. Boy, did I look for errors in the wrong place, I was sure it had to do with syscall/js.

Thanks!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.