preface

In the previous first post: juejin.cn/post/684490… You can use Go to write code, compile it into WASM, and then use WASM in JS. Is a very simple demo, this article will mainly be used to explain two aspects of knowledge

  • A brief introduction to WASM
  • Wasm is loaded in js
  • Access methods exported from WASM
  • Wasm accesses methods in JS

A brief introduction to WASM

I didn’t want to introduce wASM, because there are already many available online, but to give you a quick overview of wASM as you read through this series of articles.

Features:

  • Fast execution, close to machine language, faster execution
  • Safe, sandbox environment
  • Hardware independent
  • Language independent, there is no specific development language, you can use other high-level language development, compile layer WASM
  • Platform independent, can run in browser, Node, etc
  • Smaller size, higher transmission efficiency than JS
  • modular
  • Receiving, decoding, verifying, compiling
  • Both AOT and JIT are supported
  • Parallelism, such as decoding, validation, and compilation can be performed in parallel

Why is WASM fast? First of all, WASM is closer to machine language, which we know runs fastest on a computer because the machine can run directly without compiling, converting, and so on. Wasm, it’s a binary file, it’s very small, at least much smaller than JS, so when you load it, it’s faster than JS in the first place, right? Second, wASM can decode data as it receives it from the server. Js is to download the entire JS before the interpretation of execution.

Basic type:

  • i32
  • i64
  • f32
  • f64

There are only four basic types in WASM, so if you need to process strings, you need to convert them to arrays of type ints before WASM can process them.

Function support:

As with functions in other languages, there’s nothing to say.

Several stages:

  • Compilation, which decodes the binary into an internal representation of the module, and the actual implementation can be compiled directly into machine code.
  • Verification, the main verification after decoding results are correct, such as format, security, etc.
  • perform
    • Instantiate, define module imports, initialize exports, etc
    • Call, after the instantiation is complete, you can call the exported method

It is also important to note that WASM does not have its own specific development language, requiring you to use other languages such as Go or Rust. So, once you’ve written your code in Go or Rust, compile it into WASM so it can be used in JS.

So if you happen to know how to Go or Rust, is that an advantage? Because at least for now, there are a lot of scenarios using WASM on the front end.

Wasm is loaded in js

Let’s start with some of the WASM apis in JS. For detailed API information, see developer.mozilla.org/zh-CN/docs/…

WebAssembly global objects

This object contains all available WebAssembly functionality. If your browser doesn’t have this object, you’re probably using an ancient browser.

Right, you can see from the browser compatibility, IE is very bad (who still support IE, show of hands?). All other browsers support it.

WebAssembly.compile()

The compile method is used to compile the WASM binary into a Webassembly.module object. This should be easy to understand, right? Because it’s binary, so if you want to use it in JS, you have to convert it to something that works in JS, right? That’s what this method does.

WebAssembly.Module

The webassembly.module is compiled with the compile() method to get the output, but this output does not work, it needs to be instantiated, which is similar to class.

WebAssembly.instantiate()

This method is used to instantiate WebAssembly code, and notice that there are two ways to use this method. The first option is to pass the binary data directly to the wASM method, and the other option is to call compile and then call Instantiate.

Here’s an example: developer.mozilla.org/zh-CN/docs/… It’s pretty clear.

WebAssembly.instantiateStreaming()

The point is, if you read the previous article, you’ve seen this method. Come on, above:

This method receives a fetch Response object and initializes it directly from there, which is much more convenient than the above method.

Now that wASM is loaded into js, let’s look at how to use wASM exported methods in JS.

Access methods exported from WASM

In the above article, it seems that it is not obvious. Let’s look at another example:

If you look at the code in the screenshot above, you can see that WASM written by Go can only be run using the same JS library that Go gave you. However, in Go, you inject methods directly into the JS environment, which is a bit like exporting, but the downside is that it can pollute global variables, you know.

Take a look at the code:

js.Global().Set("test", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
	fmt.Println("test invoked")
	return nil
}))

signal := make(chan int)
<- signal
Copy the code

Change the js code in index.html to the following:

<! DOCTYPE html> <html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    <button id="test">test</button>
</body>
<script src="./wasm_exec.js"></script>
<script>
    const go = new Go()
    WebAssembly.instantiateStreaming(fetch('main.wasm'), go.importObject) .then(result => { go.run(result.instance); / / calltestmethodstest(a); }); </script> </html>Copy the code

The difference is that after go.run, I call the test function, which go injects into me.

Take a look at the execution result:

As you can see, injecting global variables or functions directly is not very friendly to your application. After all, there is the possibility of conflicts and global variable contamination. This is a bit of a trap. What’s the elegant way to do it?

First, let’s change the js content in index.html:

< script > / / used to provide to Go hung the exported object function, have to define a global variable var target = {} const Go = new Go () WebAssembly. InstantiateStreaming (fetch ('main.wasm'), go.importObject) .then(result => { go.run(result.instance); / / calltestMethods target. The test (); }); </script>Copy the code

Other content will not be posted, as above. The difference here is that on the first line, we specify a target global object, and then call test with target.test().

The test method is not available on target. Here’s the code for Go:

js.Global().Get("target").Set("test", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
	fmt.Println("test invoked")
	return nil
}))

signal := make(chan int)
<- signal
Copy the code

In the Go code, you first get the Target object from the global object, and then set a test function to that object. This can then be used in JS.

Relative to the above directly to the global object outside of functions, set up this way some relatively grace, because can mount object, we can be defined in advance, right, so in the Go, or js, all know this is used to mount the exported functions in Go, don’t like the one above, there’s no way to know you are, How do I access functions that are exported in Go, because I don’t know where to look, global objects? So how do you know if this is the one that GO mounted? Right.

Wasm accesses methods in JS

If you want to access javascript methods in WASM, it is very simple. If you want to access JAVASCRIPT methods in WASM, it is very simple. If you want to access JAVASCRIPT methods in WASM, it is very simple.

Change the js code in index.html:

<script>
    var target = {
        test() {
            console.log('test method in js');
        }
    }

    const go = new Go()
    WebAssembly.instantiateStreaming(fetch('main.wasm'), go.importObject) .then(result => { go.run(result.instance); / / calltestThe () method / / target; }); </script>Copy the code

Modify the Go code:

js.Global().Get("target").Get("test").Invoke();

signal := make(chan int)
<- signal
Copy the code

Take a look at the results:

conclusion

This article mainly introduces WASM, js accessing exported objects in WASM, and WASM accessing objects in JS. Because Go is used as the wASM development language, it may be a little different from other languages. In particular, Go mounts objects directly to the JS environment, rather than providing exports objects as described in the WASM specification. But so far, we have found that both JS and WASM can communicate with each other, so there is no hindrance for development. It is very convenient to use Go to develop WASM, and then use it in JS.

Any wrong place, welcome to correct, thank you! 🙏