WebAssembly 从C语言代码调用到JavaScript


我以前的文章 中,我们探讨了创建一个没有Emscripten管道的**WebAssembly模块的想法。在那篇文章中,我们能够从JavaScript中调用模块,但我们没有进入到反向。

如何从一个模块调用到JavaScript?

从WebAssembly模块调用Javascript

在这篇文章中,我们将尝试让WebAssembly模块调用我们JavaScript中定义的方法。

为了编译C代码,当使用的方法不在源代码中时,你需要用extern关键字定义方法的签名,如下面的例子所示。

// 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); } 

你可以运行以下命令行来构建wasm文件。

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

为了在我们的JavaScript中定义这个方法,我们只需要把它添加到env对象中,这个对象是我们作为第2个参数传递给 WebAssembly.instantiate   方法的main对象的一部分。

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

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

就像我们在从JavaScript中调用模块时需要在方法名前添加下划线一样,我们在这里也需要在方法名前添加下划线。

以下是我们的例子模块的完整HTML/JavaScript。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
  </head>
  <body>
    <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 => 
        response.arrayBuffer()
      ).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
        gModule.exports._Test(iVal); 
      }
    </script>
  </body>
</html>