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.

Will WebAssembly kill JavaScript? Maybe not just yet.

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.

It has been designed to work alongside with JavaScript, meaning, you can call WASM modules from JavaScript code.

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.

Read more on Mozilla Developer Network website.

Memory in WASM

The memory used by a WASM module to work, is represented by an ArrayBuffer of limited size. This means that it is possible from JavaScript to sandbox the memory access of a WASM module to only a given object.

It is possible to interact with this ArrayBuffer by simply writing and reading into it from JavaScript. It is also possible to extend its size.

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.

A note about AssemblyScript: it aims at giving a way to build WASM modules to people who mainly work with JavaScript. It is still an ongoing project but it fits pretty well in the modern JS ecosystem.

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.

Let’s see by ourselves if these promises are kept. We compare how fast WASM modules can go compared to JavaScript (transpiled from TypeScript) when handling:

Simple numerical values

Strings

Arrays

Side note: all performance tests have been performed with V8 6.7 in Node.js 10.5. However, the results can be easily computed in any other modern JavaScript engine too. All codes used in this article are on Github.

Numeric operations

Let’s start with a simple algorithm: a dummy counter we implement in TypeScript (with AssemblyScript types) and in Rust:

View the code on Gist.

View the code on Gist.

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.

Strings manipulation

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:

View the code on Gist.

View the code on Gist.

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:

View the code on Gist.

View the code on Gist.

We will only compare JavaScript with Rust for this one: as of today it is not easy to use arrays as parameters with AssemblyScript:

Once again, we end up with these weird results where JavaScript is the fastest.

There must be something wrong

And there is.

The raw execution of an algorithm in WASM is almost always faster than in JavaScript. However, the cost of writing data into the WASM module’s memory can be so high that it removes the benefit of using WASM in the first place.

To make sure of this, let’s run another experiment. Instead of just calling a method with parameters defined on JavaScript side, we will call a method with static parameters and loop 1000 times around that:

Strings

View the code on Gist.

View the code on Gist.

Arrays

View the code on Gist.

View the code on Gist.

Rust-based WASM alternative outruns JavaScript by far.

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.

Conclusion

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

If I could make a wish, I would like the WebAssembly specification to define a data exchange format for strings and arrays. This could be then used to pass arguments between JavaScript and WebAssembly using pieces of code that would be optimized by browser vendors.

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.

You want to get rid of JavaScript because you just don’t like this language:

I believe writing a full web application in WebAssembly at this point is: