WebAssembly vs Javascript

A comparison between WebAssembly and Javascript

WebAssembly vs Javascript

Build Status Dependabot Status

A comparison between WebAssembly and Javascript made for studying fun.

What’s in the box

Rust and WebAssembly

There are two books that fully cover this section:

In this project I’m also using wasm-bingen and wasm-pack.

Project

Folder Structure

Source code is splitted into two main folders: src that contains our Rust application and src-js that contains our Javascript application.

I tried to make their folder structure as similar as possible:

src
├── libs
   ├── mod.rs
   ├── ...
   └── primes.rs
└── main.rs

src-js
├── libs
   ├── mod.js
   ├── ...
   └── primes.js
├── ...
├── bootstrap.js
└── main.js

*/libs/mod.* is the entry point for declaring all modules. The .rs version of this file will be compiled to .wasm.

*/libs/primes.* is a module example, written both in Rust and Javascript.

*/main.* is the entry point for the application. The .rs file is the one used by cargo run command. The .js file is the one used by webpack.

./src-js/bootstrap.js is the bootstrap file for the web application that loads the main.js file asynchronously.

Rust

The first step is to install Rust. We’ll download Rust through rustup, a command line tool for managing Rust versions and associated tools.

Runnig following command we’ll install Rust and Cargo automatically. You will also need to install wasm-pack.

$ curl https://sh.rustup.rs -sSf | sh

# install `wasm-pack`
$ curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

# update dependencies
$ cargo update

Now we are able to use the following commands from our project folder.

# test .rs files
$ cargo test

# compile `src/main.rs`
$ cargo build
    Finished dev [unoptimized + debuginfo] target(s)

# or compile `src/main.rs` with optimizations
$ cargo build --release
    Finished release [optimized] target(s)

Now that we have built our code, we can run it:

$ ./target/release/wasm-vs-js-benchmark primes-get_primes 11

We can also use cargo run to compile and then run it, all in one step:

$ cargo run primes-get_primes 11

# compile and run our project with optimizations
$ cargo run --release primes-get_primes 11

Last but not least, we’ll compile our project to .wasm:

$ wasm-pack build

Now we are able to use the content of ./pkg folder for our web application.

Javascript

The goal of this project is benchmarking WebAssembly and Javascript. Some task will use big computations that takes time to execute.

Web Workers makes it possible to run a script operation in a background thread separate from the main execution thread of a web application.

The web application is bundled with Webpack.

Run following command to start it:

$ npm run build:wasm
$ npm start

Project is running at http://localhost:8080/

Unit Test

You can run unit test for Rust and Javascript, simply running npm test.

I use mocha for javascript unit test, transpiling ES6 with @babel/core, @babel/preset-env and @babel/register.

Benchmark

Rust to Native Code

The execution time of .wasm binaries is just a bit slower than the execution of same native code.

For benchmarking the native code, I use Hyperfine.

These benchmarks are recorded on a MacBook Pro (15-inch, 2016) having these specs:

$ cargo build --release

$ hyperfine --warmup 3 --export-markdown BENCHMARK.md \
    './target/release/wasm-vs-js-benchmark primes-get_primes 100000' \
    './target/release/wasm-vs-js-benchmark matrix-multiply 500 500'
CommandMean [s]Min…Max [s]
./target/release/wasm-vs-js-benchmark primes-get_primes 1000001.211 ± 0.0181.196…1.255
./target/release/wasm-vs-js-benchmark matrix-multiply 500 5000.435 ± 0.0160.417…0.469

WebAssembly vs Javascript

https://marcomontalbano.github.io/wasm-vs-js-benchmark