Geekflare is supported by our audience. We may earn affiliate commissions from buying links on this site.
Share on:

WebAssembly for Beginners Part 4: WebAssembly and JavaScript Companionship

WebAssembly and JavaScript Companionship
Invicti Web Application Security Scanner – the only solution that delivers automatic verification of vulnerabilities with Proof-Based Scanning™.

In part 4 of WebAssembly for beginners, we’ll look closely at WebAssembly and JavaScript companionship.

Here, you’ll learn how to use WebAssembly in your JavaScript. In addition, we’ll also explore WebAssembly JavaScript API.

WebAssemebly is a binary-format open standard that enables developers to run apps at native performance on browsers. If you haven’t read about it, we suggest checking out the previous parts in our guide.

Let’s get started.

Using WebAssembly With JavaScript

In our WebAssembly part 1 tutorial, we discussed how WASM works. To write high-performing code for your web app, you must use WASM APIs and functions within JavaScript. We also discussed how JavaScript frameworks could use WASM to create high-performance apps.

However, you cannot currently load WASM modules like ES6 modules using the <script type=” module”>. That’s where JavaScript comes in. It helps in loading and compiling WASM on the browser. The exact steps to do so are as below:

  • Load the .wasm bytes into ArrayBuffer or typed array.
  • Use WebAssembly.Module to compile bytes.
  • Now, instantiate WebAssembly.Module with imports to get callable exports

So, you need to get started with the pre-compiled WASM module. Here, you get plenty of choices. You can use Rust, C/C++, AssemblyScript, and even TinyGo(Go) to write your code and later transform it into a .wasm module.

Technically, WebAssembly is a compilation target for languages. This means you’ll need to write code in your choice of language and then use the generated binary code within the application (web or non-web). In addition, if you intend to use it on servers, you’ll need to use WASI for interfacing with systems.

As WebAssembly uses linear memory via an expandable array, both JavaScript and WASM can access it synchronously, giving you the ability to write feature-rich, fast apps.

WebAssembly and JavaScript Examples

Let’s use examples to learn how you can use WASM with JavaScript. 

As mentioned above, you need a pre-compiled WASM module. For this example, we’ll use Emscripten (C/C++). As WASM offers a high-performance binary format, we can run the generated code alongside JavaScript or other languages.

Tool Setup

As we’re using Emscripten, we need to get emsdk tool. It’ll allow you to compile your C/C++ code into .wasm code.

Simply run the following command in your terminal. If you don’t have GIT installed, follow our Open Source 101: Version Control System and Git guide to do so.

git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
#Output

nitt@nitt-laptop:~/Projects/WASM2$ git clone https://github.com/emscripten-core/emsdk.git
Cloning into 'emsdk'...
remote: Enumerating objects: 3566, done.
remote: Counting objects: 100% (62/62), done.
remote: Compressing objects: 100% (49/49), done.
remote: Total 3566 (delta 31), reused 38 (delta 13), pack-reused 3504
Receiving objects: 100% (3566/3566), 2.09 MiB | 2.24 MiB/s, done.
Resolving deltas: 100% (2334/2334), done.
nitt@nitt-laptop:~/Projects/WASM2$ cd emsdk
nitt@nitt-laptop:~/Projects/WASM2/emsdk$

In the emdsk folder, we call another command to get the latest ready-to-use Emscripten build. 

To do so, you need to run the following commands.

./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh
#Output

nitt@nitt-laptop:~/Projects/WASM2/emsdk$ ./emsdk install latest
Resolving SDK alias 'latest' to '3.1.31'
Resolving SDK version '3.1.31' to 'sdk-releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit'
Installing SDK 'sdk-releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit'..
Installing tool 'node-14.18.2-64bit'..
Downloading: /home/nitt/Projects/WASM2/emsdk/zips/node-v14.18.2-linux-x64.tar.xz from https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/node-v14.18.2-linux-x64.tar.xz, 21848416 Bytes
Unpacking '/home/nitt/Projects/WASM2/emsdk/zips/node-v14.18.2-linux-x64.tar.xz' to '/home/nitt/Projects/WASM2/emsdk/node/14.18.2_64bit'
Done installing tool 'node-14.18.2-64bit'.
Installing tool 'releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit'..
Downloading: /home/nitt/Projects/WASM2/emsdk/zips/1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-wasm-binaries.tbz2 from https://storage.googleapis.com/webassembly/emscripten-releases-builds/linux/1eec24930cb2f56f6d9cd10ffcb031e27ea4157a/wasm-binaries.tbz2, 349224945 Bytes
Unpacking '/home/nitt/Projects/WASM2/emsdk/zips/1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-wasm-binaries.tbz2' to '/home/nitt/Projects/WASM2/emsdk/upstream'
Done installing tool 'releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit'.
Done installing SDK 'sdk-releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit'.
nitt@nitt-laptop:~/Projects/WASM2/emsdk$ ./emsdk activate latest
Resolving SDK alias 'latest' to '3.1.31'
Resolving SDK version '3.1.31' to 'sdk-releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit'
Setting the following tools as active:
   node-14.18.2-64bit
   releases-1eec24930cb2f56f6d9cd10ffcb031e27ea4157a-64bit

Next steps:
- To conveniently access emsdk tools from the command line,
  consider adding the following directories to your PATH:
    /home/nitt/Projects/WASM2/emsdk
    /home/nitt/Projects/WASM2/emsdk/node/14.18.2_64bit/bin
    /home/nitt/Projects/WASM2/emsdk/upstream/emscripten
- This can be done for the current shell by running:
    source "/home/nitt/Projects/WASM2/emsdk/emsdk_env.sh"
- Configure emsdk in your shell startup scripts by running:
    echo 'source "/home/nitt/Projects/WASM2/emsdk/emsdk_env.sh"' >> $HOME/.bash_profile

The last command, “source ./emsdk_env.sh”. It ensures the emcc Emscripten compiler tool path is set, and you can use it to compile code.

#Output

nitt@nitt-laptop:~/Projects/WASM2/emsdk$ source ./emsdk_env.sh
Setting up EMSDK environment (suppress these messages with EMSDK_QUIET=1)
Adding directories to PATH:
PATH += /home/nitt/Projects/WASM2/emsdk
PATH += /home/nitt/Projects/WASM2/emsdk/upstream/emscripten
PATH += /home/nitt/Projects/WASM2/emsdk/node/14.18.2_64bit/bin

Setting environment variables:
PATH = /home/nitt/Projects/WASM2/emsdk:/home/nitt/Projects/WASM2/emsdk/upstream/emscripten:/home/nitt/Projects/WASM2/emsdk/node/14.18.2_64bit/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
EMSDK = /home/nitt/Projects/WASM2/emsdk
EMSDK_NODE = /home/nitt/Projects/WASM2/emsdk/node/14.18.2_64bit/bin/node
nitt@nitt-laptop:~/Projects/WASM2/emsdk$ 

Now, we need to generate the wasm code by running the following command.

emcc hello-geekflare.c -o hello-geekflare.js
#Output

nitt@nitt-laptop:~/Projects/WASM2$ emcc hello-geekflare.c -o hello-geekflare.js
shared:INFO: (Emscripten: Running sanity checks)
cache:INFO: generating system asset: symbol_lists/1c683af19e290d0b5ca7a8747d74a76f63dcb362.txt... (this will be cached in "/home/nitt/Projects/WASM2/emsdk/upstream/emscripten/cache/symbol_lists/1c683af19e290d0b5ca7a8747d74a76f63dcb362.txt" for subsequent builds)
cache:INFO:  - ok
nitt@nitt-laptop:~/Projects/WASM2$ dir
emsdk  hello-geekflare.c  hello-geekflare.js  hello-geekflare.wasm
nitt@nitt-laptop:~/Projects/WASM2$ 

As you can see, you get an output of “hello-geekflare.js” and hello-geekflare.wasm. You can check the files by running dir in the project directory.

Both these files are essential. The hello-geefklare.wasm contains the compiled code. The hell-geefklare.js file, on the other hand, has the JavaScript required to run it. As Emscripten supports web and node.js execution, we can test it out with Node.

node hello-geekflare.js
#Output

nitt@nitt-laptop:~/Projects/WASM2$ node hello-geekflare.js
Hello, GeekFlare! 
nitt@nitt-laptop:~/Projects/WASM2$ 

If you want to see it run on the web, you can generate the HTML file with Emscripten. To do so, run the following command.

emcc hello-geekflare.c -o hello-geekflare.html
#Output

nitt@nitt-laptop:~/Projects/WASM2$ emcc hello-geekflare.c -o hello-geekflare.html
nitt@nitt-laptop:~/Projects/WASM2$ 

To run the HTML file, you can use the Python 3 HTTPServer by running the following command.

python3 -m HTTP.server 8000

Now, go to http://localhost:8000/hello-geekflare.html to see the output.

Note: Most systems come pre-installed with Python. If not, you can easily install it before trying to run the Python3 server.

Using JavaScript API to Work With WASM

This section will take a closer look at JavaScript WASM API. With it, we’ll learn how to load WASM code and execute it. But first, let’s look at the code below.

fetch('hello-geekflare.wasm').then( response =>
   response.arrayBuffer())
   .then (bytes =>
       WebAssembly.instantiate(bytes))
       .then(result=>
           alert(result.instance.exports.answer()))

The above code uses the following JavaScript APIs.

  • fetch() Browser API
  • WebAssembly.instantiate

Apart from these, there are other APIs worth noting. These include:

  • WebAssembly.compile
  • WebAssembly.instance
  • WebAssembly.instantiate
  • WebAssembly.instantiateStreaming

fetch() Browser API

The fetch() API loads the .wasm network resource. If you’re trying to load it locally, you need to disable cross-origin resource sharing to load the network resource. Otherwise, you can use a node server to do it for you. To install and run a node server, run the following command.

sudo apt install npm

Next, run the following command to run the server.

npx http-server -o
#Output

http-server version: 14.1.1

http-server settings: 
CORS: disabled
Cache: 3600 seconds
Connection Timeout: 120 seconds
Directory Listings: visible
AutoIndex: visible
Serve GZIP Files: false
Serve Brotli Files: false
Default File Extension: none

Available on:
  http://127.0.0.1:8080
  http://192.168.0.107:8080
Hit CTRL-C to stop the server
Open: http://127.0.0.1:8080

[2023-01-28T19:22:21.137Z]  "GET /" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.70"
(node:37919) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated
(Use `node --trace-deprecation ...` to show where the warning was created)
[2023-01-28T19:22:21.369Z]  "GET /favicon.ico" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.70"
[2023-01-28T19:22:21.369Z]  "GET /favicon.ico" Error (404): "Not found"

It’ll open the web browser where you can see all your project files.

Now open hello-geefklare.html and run the Web Developer tools. There, open the console, and type the following.

fetch(“hello-geekflare.wasm”);

It’ll return the following promise.

#Output

Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: Response
body: (...)
bodyUsed: false
headers: Headers {}
ok: true
redirected: false
status: 200
statusText: "OK"
type: "basic"
url: "http://127.0.0.1:8080/hello-geekflare.wasm"
[[Prototype]]: Response

You can also write the following script and run it through HTML.

To run your wasm modules on the server, you need to use the following code in Node.js.

const fs = require('fs');
const run = async() => {
   const buffer = fs.readFileSync("./hello-geekflare.wasm");
   const result = await WebAssembly.instantiate(buffer);
   console.log(result.instance.exports.answer());
};

run();

We suggest reading WebAssembly JavaScript API documentation to learn more about it.

JavaScript Vs. WASM

To understand the companionship between WASM and JavaScript, we also need to compare them. At the core, WASM is faster and has a binary format for target compilation, whereas JavaScript is a high-level language. WASM’s binary code makes learning hard, but there are ways to work with WASM efficiently.

The key difference between WASM and JavaScript include the following:

  • WASM is a compiled language, whereas JS is an interpreted language. The browser must download and parse JavaScript at runtime, whereas WASM code is ready to execute with its pre-compiled code.
  • WebAssembly is a low-level language. In contrast, JavaScript is a high-level language. Being high-level, JS is easy-to-work-with. However, WASM being low-level can execute way faster than JavaScript.
  • Lastly, JavaScript benefits from its large community. So, if you’re looking for a better development experience, JS is an obvious choice. WebAssembly, on the other hand, is relatively new and hence lacks resources.

As a developer, you don’t have to worry about choosing one. This is because both JS and WASM work together and not against each other.

So, if you’re writing a high-performance app, you may want to use WebAssembly to code only the parts that need performance. The JavaScript API can help you fetch and use WASM modules directly into your JavaScript code.

Final Thoughts

In the end, WebAssembly is a great companion to JavaScript. It invites developers to create high-performance applications on the web and non-web. Moreover, it does it without trying to replace JavaScript. 

However, will WASM evolve into a complete package and replace JavaScript? Well, that’s likely, not possible, considering the WebAssembly goals. However, the idea of WebAssembly to replace JavaScript in the future is not entirely refutable.

Next, check out the best JavaScript (JS) UI libraries to build modern applications.

Thanks to our Sponsors
More great readings on Development
Power Your Business
Some of the tools and services to help your business grow.
  • Invicti uses the Proof-Based Scanning™ to automatically verify the identified vulnerabilities and generate actionable results within just hours.
    Try Invicti
  • Web scraping, residential proxy, proxy manager, web unlocker, search engine crawler, and all you need to collect web data.
    Try Brightdata
  • Monday.com is an all-in-one work OS to help you manage projects, tasks, work, sales, CRM, operations, workflows, and more.
    Try Monday
  • Intruder is an online vulnerability scanner that finds cyber security weaknesses in your infrastructure, to avoid costly data breaches.
    Try Intruder