preface

After I started working on WebAssembly, I read a lot on Google. I feel that the use, introduction, and meaning of WebAssembly are vague and general. I feel that after reading the article, the harvest did not reach my expectations. Either I could not succeed in putting the examples in the article into practice, or I did not know what was going on and looked blind. This article was born with the attitude that business drives technology. The previous section is mainly about the background of WebAssembly, how WebAssembly emerged, and what the advantages are. If you want to start working on the code, skip to the last section.

What is WebAssembly?

define

So let’s define it first.

WebAssembly or WASM is a new format that is portable, small, fast to load, and Web compatible

example

Of course, I know that even if you read the definition, you wouldn’t know what WebAssembly is. Without further ado, let’s take a look at what WebAssembly is all about with a simple example.

On the left of the figure above is a recursive function implemented in C++. In the middle is the hexadecimal Binary Code. To the right is the instruction text. What the hell does this have to do with WebAssembly? In fact, the middle hexadecimal Binary Code is WebAssembly.

Compile the target

As you can see, the writability and readability are unimaginably poor. That’s because WebAssembly isn’t for you to hand-roll code, WebAssembly is a build target. What is a compile target? When we write TypeScript, the resulting JavaScript file that Webpack packs is the compilation target. As you might have guessed, the Binary shown above is the C++ code on the left that has been compiled by the compiler.

The origin of the WebAssembly

Performance bottleneck

As business requirements become more and more complex, front-end development logic becomes more and more complex, and the corresponding amount of code becomes more and more. Accordingly, the whole project takes longer and longer to get started. On poor computers, it can take more than 10 seconds to start a front-end project. These are actually good, it shows that the front-end is more and more attention, more and more people began to front-end development.

But in addition to the complexity of the logic and the amount of code, there is another reason that the language itself is flawed, JavaScript does not have static variable types. Brendan Eich, the author of the interpreted programming language, rushed to create the language that is now widely used, so much so that the history of JavaScript is in some ways a history of filling holes. Why no static typing is inefficient. This will involve some knowledge of JavaScript engines.

Problems with static variable types

This is the structure of ChakraCore, the JavaScript engine for the Microsoft Edge browser. Let’s take a look at what happens to our JavaScript code in the engine.

  • The JavaScript file will be downloaded.
  • Then go to the Parser, which turns the code into an AST (abstract syntax tree).
  • Based on the abstract syntax tree, the Bytecode Compiler generates Bytecode that the engine can directly read and execute.
  • The bytecode enters the translator, which translates the bytecode line by line into highly efficient Machine Code.

During project running, the engine will optimize the function that is executed more times. The engine will compile its Code into Machine Code and package it to the just-in-time (JIT) Compiler at the top. The function will be executed next Time. It will execute the compiled Machine Code directly. But with JavaScript’s dynamic variables, it could be Array one second and Object the next. The last time the engine was optimized, it was useless, and it had to be optimized again.

Asm. Js

So to solve this problem, WebAssembly’s predecessor, asm.js, was born. Asm. js is a strict subset of Javascript. Legitimate asm.js code must be legitimate Javascript code, but not vice versa. As with WebAssembly, asm.js is not for you to hand-roll code, asm.js is a compile target. Its readability and readability is better than WebAssembly, but it is still unacceptable to developers.

Asm. js enforces static typing, for example.

function asmJs() {
    'use asm';
    
    let myInt = 0 | 0;
    let myDouble = +1.1;
}
Copy the code

Why does asm.js have static types? Because like 0 | 0, represent the data of this is an Int, and + 1.1 represents a Double data.

Asm. js does not solve all problems

For those of you who have questions, isn’t that a problem solved? So why WebAssembly? What problem does WebAssembly solve? Take a look at the ChakraCore engine structure above. No matter how well asm.js does with static typing, it still has to go through the Parser and ByteCode Compiler, two of the most time-consuming steps in the engine’s execution of JavaScript code. WebAssembly does not go through these two steps. This is why WebAssembly is faster than asm.js.

WebAssembly was born

So in 2015, we welcomed WebAssembly. WebAssembly is code compiled by the compiler, small and fast to start with. Completely syntactically detached from JavaScript, with a sandboxed execution environment. WebAssembly also enforces static typing and is the compile target of C/C++/Rust.

The advantage of WebAssembly

Performance comparison between WebAssembly and asm.js

The figure below is a BenchMark comparison of Unity WebGL start-up times with and without WebAssembly, as a reference. As you can see, the performance difference between WebAssembly and asm.js is 2x in FireFox, 3x in Chrome, and even 6x in Edge. The comparison also shows that WebAssembly V1 (Node >= 8.0.0) is now supported by all major browsers.

Compare that to JavaScript

I myself compared the WebAssembly version and the native JavaScript version of the recursion-unoptimized Fibonacci function in a new project using create-React-App. The following figure shows the performance of the two functions at values 45, 48, and 50.

WebAssembly in large projects

There are many examples here, such as AutoCAD, GoogleEarth, Unity, Unreal, PSPDKit, WebPack and so on. Take a few of them briefly.

AutoCAD

For a long time, there was no Web version of the drawing software, for two reasons. One, the Web performance really didn’t meet their needs. Second, before WebAssembly came out, AutoCAD was implemented in C++, and moving it to the Web meant rewriting all their code, which was very costly.

After The release of WebAssembly, AutoCAD was able to use the compiler to directly compile its code accumulated for more than 30 years into WebAssembly, and its performance was greatly improved based on the previous common Web applications. These are the reasons that enabled AutoCAD to move its applications from the Desktop to the Web.

Google Earth

Google Earth, also known as Google Earth, needs to display a lot of 3D images and has high performance requirements, so it adopts some Native technologies. Initially, even Google Chrome did not support a Web version, requiring a separate download of the Google Earth Destop app. After WebAssembly, Google Earth launched a version of the Web. The next browser to run Google Earth is said to be FireFox.

Unity and Unreal Game Engine

Here are two YouTube links for your own experience, everyone pay attention to scientific Internet.

  • Unity WebGL’s stamp here
  • Unreal engine poke here

WebAssembly to replace JavaScript?

The answer is no, as shown in the chart below.

You can see that this is a collaborative relationship. WebAssembly is designed to complement JavaScript, not to replace it. WebAssembly brings many programming languages to the Web. But JavaScript will remain in place because of its incredible capabilities.

When to use WebAssembly?

With all that said, when exactly should I use it? To sum up, there are two points in most cases.

  • Apps/modules/games with high performance requirements
  • A simple example of using C/C++/Rust/Go libraries on the Web. If you’re implementing a Web version of Instagram or Facebook, you want to be more efficient. You can then implement the tools for compressing, decompressing, and processing images in C++ and compile them back to WebAssembly.

Several development tools for WebAssembly

  • AssemblyScript. Direct compilation of TypeScript to WebAssembly is supported. This for many front end students, the threshold of entry is still very low.
  • Emscripten. It’s the soul tool of WebAssembly. I’ve talked a lot about compilers. This is the compiler. Compile other high-level languages into WebAssembly.
  • WABT. WebAssembly is a tool that translates WebAssembly into bytecode and text formats, making it easier for developers to understand what wASM is actually doing.

The significance of WebAssembly

In my personal understanding, WebAssembly is not meant to replace JavaScript and rule the world. I’ll just sum it up with two points.

  • Better performance for the Web
  • Gives the Web more possibilities for WebAssembly performance issues, which have been covered at length before. More likely, as The technology of WebAssembly becomes more and more mature, more applications will be moved from the Desktop to the Web, which will make the already very powerful Web richer and more powerful.

WebAssembly field

To do this in practice, you need to install the Emscripten compiler mentioned above and then follow these steps to install it. The following steps default to Emscripten installed.

WebAssembly in Node

Import Emscripten environment variables

Go to your emscripten installation directory and execute the following code.

source emsdk/emsdk_env.sh
Copy the code

Create a C file

Implement a summation file test.c in C, as follows.

int add(int a, int b) {
	return a + b;
}
Copy the code

Compile C files using Emscripten

Execute the following code in the same directory.

emcc test.c -Os -s WASM=1 -s SIDE_MODULE=1 -o test.wasm
Copy the code

C is our input file, -os means that the compilation needs to be optimized, -s WASM=1 means that the output WASM file, because the default output is asm.js, -s SIDE_MODULE=1 means that only this module is needed. Don’t give me any other code, -o test.wasm is our output file.

After successful compilation, test.wasm will be generated in the current directory.

Write the code to call in Node

Create a new js file, test.js. The code is as follows.

const fs = require('fs');
let src = new Uint8Array(fs.readFileSync('./test.wasm'));
const env = {
	memoryBase: 0.tableBase: 0.memory: new WebAssembly.Memory({
		initial: 256
	}),
	table: new WebAssembly.Table({
		initial: 2.element: 'anyfunc'
	}),
	abort: (a)= > {throw 'abort'; } } WebAssembly.instantiate(src, {env: env})
.then(result= > {
	console.log(result.instance.exports._add(20.89));
})
.catch(e= > console.log(e));
Copy the code

Perform the test. Js

Run the following code.

node test.js
Copy the code

Then you can see the output 109.

WebAssembly in React

Method calls via FETCH

I’m going to fetch directly. The general method of calling is as follows.

const fibonacciUrl = './fibonacci.wasm';
const {_fibonacci} = await this.getExportFunction(fibonacciUrl);
Copy the code

The specific code of getExportFunction is as follows.

getExportFunction = async (url) => {
    const env = {
      memoryBase: 0.tableBase: 0.memory: new WebAssembly.Memory({
        initial: 256
      }),
      table: new WebAssembly.Table({
        initial: 2.element: 'anyfunc'})};const instance = await fetch(url).then((response) = > {
      return response.arrayBuffer();
    }).then((bytes) = > {
      return WebAssembly.instantiate(bytes, {env: env})
    }).then((instance) = > {
      return instance.instance.exports;
    });
    return instance;
};
Copy the code

This is called by import C file

Import dependencies by importing them.

import wasmC from './add.c';
Copy the code

Then make the call. The specific way is as follows.

wasmC({
  'global': {},
  'env': {
    'memoryBase': 0.'tableBase': 0.'memory': new WebAssembly.Memory({initial: 256}),
    'table': new WebAssembly.Table({initial: 0.element: 'anyfunc'})
  }
}).then(result= > {
  const exports = result.instance.exports;
  const add = exports._add;
  const fibonacci = exports._fibonacci;
  console.log('C return value was', add(2.5643));
  console.log('Fibonacci', fibonacci(2));
});
Copy the code

The detailed code is here. Welcome to Star.

Write in the back

There are more and more technologies available today, but actually there is less and less to use at work. In fact, some of the output technologies of many large factories are driven by business scenarios. Instead of building a wheel out of nothing. So summed up down for their own is the best. This is not to say that you don’t understand new technology. It’s necessary to understand new technology and keep up with it. Just because we don’t need it right now doesn’t mean we don’t need it. On the contrary, when we encounter similar business scenarios in the future, we will have one more option and can be treated more calmly.

Previous articles:

  • How do I integrate JWT authentication into SpringBoot
  • Build a SpringBoot backend project framework from scratch

Related:

  • Personal website: Lunhao Hu
  • Wechat Official Account: full stack notes of SH (or directly search for wechat LunhaoHu in the interface of adding official account)