WebAssembly is known for its speed capabilities and this article will put it to the test to better understand what are the best applications to start using WebAssembly today. We will compare the performance of WebAssembly with C/C++, Rust, and TypeScript.
What is WebAssembly?
If you are already familiar with the concepts behind WebAssembly, you can safely skip this part.
WebAssembly (often shortened as WASM) is a new web standard. It defines a way to create modules from diverse programming languages and run them in a web browser.
You can start to play with WASM right now in your web browser thanks to a very cool open source project: The WebAssembly studio.
It is designed to run close to native speed. In this article, we will see how accurate is this statement so far.
Memory in WASM
Building and using WebAssembly modules
Building and using modules
There are multiple ways to create WASM modules. Obviously one could write a module in Webassembly Text Format but this can get pretty hard to do at some point (would you write your code in assembly yourself?). Thankfully, a few programming languages can be compiled to WASM:
- C/C++, using Emscripten.
- Rust, you want to check the rustwasm repo
- AssemblyScript, this is a subset of TypeScript that actually compiles to WASM
Of course, there are other tools, but these 3 are the one I played with.
In the end, all these tools can be used to obtain:
- A binary WASM module
- A JS script to call the WASM module within Node.js or a browser
Let’s talk performance 🚀
WebAssembly is usually branded as a solution to run high-performance modules in a web browser. It can rely on decades of experience in compilation and optimization to produce fast results.
- Simple numerical values
Let’s start with a simple algorithm: a dummy counter we implement in TypeScript (with AssemblyScript types) and in Rust:
Using the Benchmark module, we compare the performance of our three functions with 100000 as the parameter:
In this case, Rust outruns all competitors by far.
Now that we’ve played a bit with simple types, let’s see how the technologies behave with a more complex set of data, let’s run the following code:
We benchmark it with the parameters
'hello world', 'world':
There is something weird, how could JS be that fast compared to compiled languages? Especially Rust? We need to go deeper.
Playing with Arrays
Let’s try one last thing with complex data structures before going further:
There must be something wrong
And there is.
The cost of writing complex data structures in WASM memory is pretty high, for instance, to pass a simple string to a WASM module, you need to:
- Encode this string (for instance in UTF-16)
- Obtain a free piece of memory (equivalent to a malloc)
- Write the encoded string into it
Based on what memory management algorithm is used, this can get pretty slow. Also, the longer the string, the slower the operation.
WebAssembly is, without doubt, a very exciting technology. I am looking forward to seeing how this technology will mature and be used. Currently, some topics like Garbage Collection are yet to be fully specified, but I am confident a powerful and usable ecosystem is to be built here.
As of today, you can safely decide to use WebAssembly in your projects:
- Major browsers (and Node.js) support it natively
- Tooling is relatively easy to use
However, you need to make sure why you would want to use WebAssembly in a web project:
You are seeking performance boosts:
WebAssembly is probably a good choice either if you are only handling numeric data or if your algorithm is complex enough for the cost of passing arguments to the WebAssembly module to become negligible.
You want to ship obfuscated code in browsers:
This is probably a legitimate use case for WebAssembly modules. I am pretty excited about seeing a reverse engineering scene appearing around this technology.
I believe writing a full web application in WebAssembly at this point is:
- Painful: you will not have any debugger
- Slow: you will spend a lot of time dealing with trivial topics
- Counter-productive: your framework will expose DOM-related methods and these calls will be pretty slow.