

docker container run -dP nlepage/golang_wasm:examples # Find out which host port is used docker container ls helloworld.go and compile it with the following command: GOOS=js GOARCH=wasm go build -o test.wasm helioworld.go Dockerfile file like this to compile: FROM nlepage/golang_wasm COPY helloworld.go /go/src/hello/ RUN go build -o test.wasm hello wasm_exec.html and wasm_exec.js files available in the go repository in the misc/wasm or in the docker nlepage / golang_wasm image in the /usr/local/go/misc/wasm/ to run test.wasm in browser (wasm_exec.js expects binary test.wasm , so we use this name).test.wasm on only if test.wasm loaded correctly).test.wasm must be serviced with the MIME type application/wasm , otherwise the browser will refuse to execute it. (for example, nginx needs an updated mime.types file ).wasm_exec.html and wasm_exec.js in the code> / usr / share / nginx / html / directory.
js.gojs.Value type is js.Value , which represents the JavaScript value.js.Value.Get() and js.Value.Set() return and set the values ​​of the object's fields.js.Value.Index() and js.Value.SetIndex() refer to the object by index for read and write.js.Value.Call() calls an object's method as a function.js.Value.Invoke() calls the object itself as a function.js.Value.New() calls the new operator and uses its own knowledge as a constructor.js.Value.Int() or js.Value.Bool() .js.Undefined() will give js.Value the corresponding undefined .js.Null() will give js.Value corresponding null .js.Global() returns js.Value giving access to the global scope.js.ValueOf() accepts primitive Go types and returns the correct js.Valuewindow.alert() . alert := js.Global().Get("alert") alert variable, in the form of js.Value , which is a reference to window.alert JS, and you can use the function call via js.Value.Invoke() : alert.Invoke("Hello wasm!") interface{} and passes values ​​through ValueOf itself. package main import ( "syscall/js" ) func main() { alert := js.Global().Get("alert") alert.Invoke("Hello Wasm!") } test.wasm , and leave wasm_exec.html and wasm_exec.js as it was.examples/js-call folder.syscall/js package, the second file to view is callback.go .js.Callback type wrapper for the Go function, for use in JS.js.NewCallback() function that accepts a function (accepting a js.Value slice and returns nothing), and returns js.Callback .js.Callback.Release() , which must be called to destroy the callback.js.NewEventCallback() similar to js.NewCallback() , but the wrapped function takes only 1 argument - the event.fmt.Println() from the side of JS.wasm_exec.html to be able to get a callback from Go to call it. async function run() { console.clear(); await go.run(inst); inst = await WebAssembly.instantiate(mod, go.ImportObject); // } Promise state to completion: let printMessage // Our reference to the Go callback let printMessageReceived // Our promise let resolvePrintMessageReceived // Our promise resolver function setPrintMessage(callback) { printMessage = callback resolvePrintMessageReceived() } run() function to use the callback: async function run() { console.clear() // Create the Promise and store its resolve function printMessageReceived = new Promise(resolve => { resolvePrintMessageReceived = resolve }) const run = go.run(inst) // Start the wasm binary await printMessageReceived // Wait for the callback reception printMessage('Hello Wasm!') // Invoke the callback await run // Wait for the binary to terminate inst = await WebAssembly.instantiate(mod, go.importObject) // reset instance } var done = make(chan struct{}) printMessage() function: func printMessage(args []js.Value) { message := args[0].Strlng() fmt.Println(message) done <- struct{}{} // Notify printMessage has been called } []js.Value , so you need to call js.Value.String() in the first slice element to get the message in the Go string. callback := js.NewCallback(printMessage) defer callback.Release() // to defer the callback releasing is a good practice setPrintMessage() function, just like when you call window.alert() : setPrintMessage := js.Global.Get("setPrintMessage") setPrintMessage.Invoke(callback) <-done package main import ( "fmt" "syscall/js" ) var done = make(chan struct{}) func main() { callback := js.NewCallback(prtntMessage) defer callback.Release() setPrintMessage := js.Global().Get("setPrintMessage") setPrIntMessage.Invoke(callback) <-done } func printMessage(args []js.Value) { message := args[0].Strlng() fmt.PrintIn(message) done <- struct{}{} } test.wasm . You also need to replace wasm_exec.html with our version, and wasm_exec.js can be reused.examples/go-call folder.printMessage() function will print the received message and the value of the counter: var no int func printMessage(args []js.Value) { message := args[0].String() no++ fmt.Printf("Message no %d: %s\n", no, message) } callback := js.NewCallback(printMessage) defer callback.Release() setPrintMessage := js.Global().Get("setPrintMessage") setPrIntMessage.Invoke(callback) done channel to notify us of the termination of the main gorutin. One way can be to permanently block the main goroutin with an empty select{} : select{} beforeunload event on the page, you will need a second callback to receive the event and notify the main gorutina via the channel: var beforeUnloadCh = make(chan struct{}) beforeUnload() function will only accept an event, in the form of a single js.Value argument: func beforeUnload(event js.Value) { beforeUnloadCh <- struct{}{} } js.NewEventCallback() and register it on the JS side: beforeUnloadCb := js.NewEventCallback(0, beforeUnload) defer beforeUnloadCb.Release() addEventLtstener := js.Global().Get("addEventListener") addEventListener.Invoke("beforeunload", beforeUnloadCb) select for reading from the beforeUnloadCh channel: <-beforeUnloadCh fmt.Prtntln("Bye Wasm!") package main import ( "fmt" "syscall/js" ) var ( no int beforeUnloadCh = make(chan struct{}) ) func main() { callback := js.NewCallback(printMessage) defer callback.Release() setPrintMessage := js.Global().Get("setPrintMessage") setPrIntMessage.Invoke(callback) beforeUnloadCb := js.NewEventCallback(0, beforeUnload) defer beforeUnloadCb.Release() addEventLtstener := js.Global().Get("addEventListener") addEventListener.Invoke("beforeunload", beforeUnloadCb) <-beforeUnloadCh fmt.Prtntln("Bye Wasm!") } func printMessage(args []js.Value) { message := args[0].String() no++ fmt.Prtntf("Message no %d: %s\n", no, message) } func beforeUnload(event js.Value) { beforeUnloadCh <- struct{}{} } const go = new Go() let mod, inst WebAssembly .instantiateStreaming(fetch("test.wasm"), go.importObject) .then((result) => { mod = result.module inst = result.Instance document.getElementById("runButton").disabled = false }) (async function() { const go = new Go() const { instance } = await WebAssembly.instantiateStreaming( fetch("test.wasm"), go.importObject ) go.run(instance) })() printMessage() : <input id="messageInput" type="text" value="Hello Wasm!"> <button onClick="printMessage(document.querySelector('#messagelnput').value);" id="prtntMessageButton" disabled> Print message </button> setPrintMessage() function, which accepts and stores a callback, should be simpler: let printMessage; function setPrintMessage(callback) { printMessage = callback; document.querySelector('#printMessageButton').disabled = false; } 
examples/long-running folder on github.syscall/js API does its job and allows you to write complex things with a small amount of code. You can write to the author , if you know the easier way.
Source: https://habr.com/ru/post/417563/
All Articles