WebAssembly Demystified
“WebAssembly” is a new type of code that runs on your browser. There is a lot of hype surrounding WebAssembly and how it’s going to change the way we code for the web. But how does it work? That’s what I will be covering in this article.
Why WebAssembly?
In a world where JavaScript is getting more and more popular, why do we need a new language like WebAssembly?
We need WebAssembly because it fills a gap that JavaScript is just not able to fill. It’s still too hard to express some of the things we may want to do with JavaScript, and the features we would need to make it easy might just add complexity to a language that already confuses many users. For example CPU and GPU intensive tasks like image/video manipulation, games and machine learning are much slower on the web when compared to native compiled code.
The original idea behind the creation of WebAssembly was to bring near-native level performance to the web and liberate it from the stranglehold that JavaScript has over the web. But over the course of time, it has turned into something that can be used alongside JavaScript when consistent, fast performance is required.
WebAssembly is also a replacement for native browser plugins (like adobe flash and adobe reader). It also enables us to use existing code in other languages directly on the web.
In a nutshell, WebAssembly provides a way to write specialized, fast code once in a while when we really need a boost in performance.
So, What Exactly is WebAssembly?
In technical terms, WebAssembly is a compiler target(output after compiling a high-level language) for programs on the Web.
If that doesn’t make any sense, WebAssembly is another language that can run on the browser. It’s a platform-independent code that sits just above machine code, this means that it can easily be converted to machine code depending on the type of system(ARM or x86). WebAssembly has a text format that is human readable, this is quite similar to native assembly code.
You can quickly explore WebAssembly code using the online tool WebAssembly Explorer. Here is an example of a square function in WebAssembly.
We can use compilers to convert a high-level language like C/C++ to WebAssembly. This means that we don’t need to directly write code in WebAssembly, but the textual representation is still there if you want to take a quick look.
So coming back to the question, what exactly is WebAssembly?
- It’s a new language that runs on the web alongside JavaScript.
- It’s a compilation target for other languages.
- It lets us take advantage of all the code that is there outside of web and JavaScript.
- It’s a way to improve the performance of web applications.
How WebAssembly works?
Before we go deep into how WebAssembly works, let's understand how the JavaScript engine works and how it optimises execution of your code on the fly.
Dynamic typing and ease of use make JavaScript one of the most popular programming languages in the world. But this dynamically typed system also limits the number of optimisations that can be applied ahead of time. This means that there is an inherent overhead with JavaScript that is very hard to optimise.
Just In Time(JIT) Compiler
To make JavaScript faster browser vendors started implementing JITs(Just in time compilers) to their browser engines. This helps speed up JavaScript execution many folds.
Let's briefly understand how modern JavaScript engines optimise performance. Most JavaScript engines consist of multiple threads.
- The main thread that will parse, compile and execute the code.
- A separate thread that will create optimised native code(optimising compiler).
- A profiler or monitor that keeps track of the executing code for opportunities to optimise.
- And threads for garbage collection.
In the beginning, the engine converts Javascript to bytecode without any optimisations. This allows the execution to start immediately.
The profiler will monitor the executing code for chunks that can be optimised to improve performance. Then in another thread, the engine will start optimising frequently executing code by creating optimised architecture-specific machine code. This code replaces the executing code, which in turn makes JavaScript run faster.
These optimisations add overheads to the execution of JavaScript. Usually, these overheads of optimisation are outweighed by the boost in performance.
During some of these optimisations, the engine makes assumptions about data types that help improve performance. But JavaScript is a dynamic language and by nature, a variable can be of any type. We can have an array in which all elements are integers except one. The engine will have checks in place to catch these cases, but these will lead to overheads. When the engine realises that the assumptions were wrong it will discard the compiled code resulting in deoptimization. This leads to waste of time and inconsistent performance.
In normal circumstances, modern JavaScript engines can provide a big performance improvement, but it cannot always guarantee consistent performance.
How the JavaScript engine spends its time:
Overheads of JITs
- Optimization and deoptimization
- Memory used for the monitor’s bookkeeping and recovery information for when bailouts happen
- Memory used to store baseline and optimized versions of a function
WebAssembly
It’s a “Low-Level Binary Format” for the web that solves some of the overheads and performance issues of JavaScript.
We don’t have to change the way we code for the web in order to use Web assembly, we can make use of WebAssembly by importing it as a module. As a developer, we don’t necessarily need to know the inner workings of a module to use it. WebAssembly will help library authors and application developers to write code in a typed language that has consistent performance and can run on the web just like JavaScript.
WebAssembly is not the native assembly code that runs directly on your machine. But it’s machine code for a conceptual machine. This lets us deliver WebAssembly code across the web and run it on all types of devices.
WebAssembly Explorer: https://mbebenita.github.io/WasmExplorer/
“.wasm “ is the file type for WebAssembly code. Although you can write WebAssembly code, it’s more practical to compile a high-level language like C/C++ to wasm. We can make use of the Emscripten compiler or web pack to compile to WebAssembly and import it as a module.
WebAssembly eliminates the overheads and performance issues that are inherent with a dynamically typed language like JavaScript. This reduces the number of steps the browser has to go through to execute WebAssembly.
Limitations of WebAssembly
Although WebAssembly seems like the next big thing, it still has a long way to go. As of now, there are limitations that will make it harder for everyone to use WebAssembly.
As of now working directly with WebAssembly is complicated because it has only four primitive types and they are all numbers — integers and floats (i32, i64, f32 and f64). This means passing complex data types between JavaScript and WebAssembly is not straightforward.
In order to use complex data types, you will need to encode the data into an array of numbers and add them to the shared memory. As of now making a lot of calls through JavaScript is not very fast, this is likely going to change in the future. But for now, we can think of WebAssembly as an isolated system that can be used to offload chunks of work.
Because of this complexity in handling data, most Library authors will create JavaScript wrapper functions around web assembly code. This means that a web developer won’t have to worry about WebAssembly, they will import and use these libraries like a normal JavaScript library.
Why WebAssembly is faster than Js.
- Less time to download, because it’s more compact.
- Web assembly code is likely to be smaller than equivalent JavaScript.
- Parsing is faster since it’s already a byte code.
- Compiling is faster since most of it was already done beforehand.
- Many optimizations are already done during the compile phase rather than during runtime.
- Depending on the application, it can run 10-800% faster.
Status of WebAssembly right now?
- WebAssembly 1.0(MVP) has shipped in 4 major browser engines.
- MVP provides enough to make WebAssembly fast and usable.
- You can compile and run already existing C/C++ code to wasm.
More info about the MVP release can be found at webassembly.org.
What’s Next?
- Threads
- Exception handling
- Garbage collection
- ECMAScript module integration
- Dom integration
- Fixed-width SIMD
- And a lot more
Check out future features from webassembly.org for more details.
Use cases
- Cross compile existing libraries for the web.
- Image/Video editing.
- Games.
- Image recognition/Computer vision.
More use cases can be found at webassembly.org.
Takeaways
- WebAssembly doesn’t replace JavaScript.
- It’s a step in the right direction to make the web a truly universal platform.
- It is useful for doing computational tasks.
- It will enable new and interesting use cases for the web.
- As a developer, you might never use it directly.
Resources
These are some of the resources that I went through to learn about WebAssembly.
Interesting Reads
- Webassembly.org
- MDN: WebAssembly
- Porting Examples and Demos
- A cartoon intro to WebAssembly by Lin Clark
- How JavaScript and V8 engine works by Alexander Zlatkov
- Why WebAssembly? by Andreas Rossberg
- WebAssembly: How and why by Milica Mihajlija
Interesting Talks
- WebAssembly: Disrupting JavaScript
- Lin Clark: A Cartoon Intro to WebAssembly | JSConf EU 2017
- Lin Clark: WebAssemblys Post MVP Future (2019 and Beyond)