WebAssembly: Calling Into JavaScript From Bare-Bones C Code

DZone 's Guide to

WebAssembly: Calling Into JavaScript From Bare-Bones C Code

So you're working with WebAssembly and just have a few bits and pieces running in C, but want to call into JavaScript... read on to learn how!

· Web Dev Zone ·
Free Resource

In my previous article, we explored the idea of creating a bare-bones WebAssembly module with no Emscripten plumbing. In that article, we were able to call into the module from JavaScript but we didn't get into the reverse:

How does one call into JavaScript from a module?

Calling Into Javascript From a WebAssembly Module

In this article, we're going to try and get a WebAssembly module to call a method that's defined in our JavaScript.

In order to compile C code, when the method being used isn't in the source code, you need to define the method signature using the extern keyword as shown in the following example:

// Define the JavaScript method's signature that we're going to be calling.
extern void CallJS(int iVal);

// A method that the JavaScript will call into to trigger our code
// that will in turn call a JavaScript method passing along the value
// received.
void Test(int iVal){ CallJS(iVal); } 

You can run the following command line to build the wasm file:

 emcc test.c -s WASM=1 -s SIDE_MODULE=1 -O1 -o test.wasm 

To define the method in our JavaScript, we just need to add it to the env object that is part of the main object that we pass as the 2nd parameter to the WebAssembly.instantiate method:

var importObject = { 
  'env': { 
    // ... (other properties/methods of this object)

    '_CallJS': function(iVal){ alert("value received: " + iVal.toString()); } 

Just like how we needed to add an underscore character before the method name when calling into the module from JavaScript, we also need to include an underscore before the method name here.

The following is the full HTML/JavaScript for our example module:

<!DOCTYPE html>
    <meta charset="utf-8"/>
    <input type="text" id="txtValue" />
    <input type="button" value="Pass Value" onclick="PassValue();" />

    <script type="text/javascript">
      var gModule = null;

      var importObject = { 
        'env': { 
          'memoryBase': 0,
          'tableBase': 0,
          'memory': new WebAssembly.Memory({initial: 256}),
          'table': new WebAssembly.Table({initial: 0, element: 'anyfunc'}),

          '_CallJS': function(iVal){ alert("value received: " + iVal.toString()); } 

      fetch('test.wasm').then(response => 
      ).then(bytes => 
        WebAssembly.instantiate(bytes, importObject) 
      ).then(results => { 
        gModule = results.instance; // Hold onto the module's instance so that we can reuse it

      function PassValue(){ 
        // Get the value from the textbox (convert the value from a string to an int)
        var iVal = parseInt(document.getElementById("txtValue").value,10);

        // Call the method in the module
web assembly ,emscripten ,javascript ,web dev

Published at DZone with permission of Gerard Gallant , DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}