WebAssembly - "Hello World"



本章我们将编写一个简单的 C 程序,将其转换为 .wasm 文件,并在浏览器中执行该文件,以获取文本“Hello World”。

我们将使用 wasm explorer 工具将 C 程序转换为 .wasm,并在我们的 .html 文件中使用该 .wasm 文件。

Wasm explorer 工具位于 https://mbebenita.github.io/WasmExplorer/,如下所示:

C Code

我们将使用的 C 代码如下:

#include <stdio.h>
char *c_hello() {
   return "Hello World"; 
}

使用以下 C 代码更新 wasm explorer 中的第一个代码块:

Update First Block

点击“编译”按钮,编译到 WASM、WAT 和 Firefox x86 WebAssembly,如下所示:

Compile

使用“下载”按钮获取 .wasm 文件,并将其保存为 **firstprog.wasm**。

创建一个名为 firstprog.html 的 .html 文件,如下所示:

<!doctype html>
<html>
   <head>
      <meta charset="utf-8"> 
      <title>WebAssembly Hello World</title> 
   </head> 
   <body>
      <div id="textcontent"></div>     
      <script type="text/javascript"> 
         //Your code from webassembly here
      </script> 
   </body>
</html>

现在让我们使用 firstprog.wasm 从 C 函数 c_hello() 读取 helloworld。

步骤 1

使用 fetch() api 读取 firstprog.wasm 代码。

步骤 2

使用 **ArrayBuffer** 将 .wasm 代码转换为 ArrayBuffer。ArrayBuffer 对象将返回一个固定长度的二进制数据缓冲区。

目前的代码如下:

<script type="text/javascript"> 
   fetch("firstprog.wasm") .then(bytes => bytes.arrayBuffer()) 
</script>

步骤 3

使用 **WebAssembly.compile(buffer)** 函数将 ArrayBuffer 中的字节编译成模块。

代码如下:

<script type="text/javascript">
   fetch("firstprog.wasm")
   .then(bytes => bytes.arrayBuffer())
   .then(mod => WebAssembly.compile(mod))
</script>

步骤 4

要获取模块,我们必须调用 webassembly.instance 构造函数,如下所示:

<script type="text/javascript">     
   fetch("firstprog.wasm") 
   .then(bytes => bytes.arrayBuffer())
   .then(mod => WebAssembly.compile(mod))
   .then(module => {return new WebAssembly.Instance(module) }) 
</script>

步骤 5

现在让我们在浏览器中查看实例的详细信息。

<script type="text/javascript"> 
   fetch("firstprog.wasm") .then(bytes => bytes.arrayBuffer()) 
   .then(mod => WebAssembly.compile(mod)) .then(module => {
      return new WebAssembly.Instance(module) 
   }) 
   .then(instance => {
      console.log(instance);
   }); 
</script>

console.log 的详细信息如下所示:

Console.log

要从函数 c_hello() 获取字符串“Hello World”,我们需要在 javascript 中添加一些代码。

首先,获取内存缓冲区详细信息,如下所示:

let buffer = instance.exports.memory.buffer;;

缓冲区值必须转换为类型化数组,以便我们可以从中读取值。缓冲区中包含字符串 Hello World。

要转换为类型化数组,请调用 Uint8Array 构造函数,如下所示:

let buffer = new Uint8Array(instance.exports.memory.buffer);

现在,我们可以在 for 循环中从缓冲区读取值。

现在让我们通过调用我们编写的函数来获取读取缓冲区的起始点,如下所示:

let test = instance.exports.c_hello();

现在,test 变量具有读取字符串的起始点。WebAssembly 没有字符串值,所有内容都存储为整数。

因此,当我们从缓冲区读取值时,它们将是整数值,我们需要使用 javascript 中的 fromCharCode() 将其转换为字符串。

代码如下:

let mytext = ""; 
for (let i=test; buffer[i]; i++){ 
   mytext += String.fromCharCode(buffer[i]);
}

现在,当您在控制台中输出 mytext 时,您应该会看到字符串“Hello World”。

示例

完整的代码如下:

<!doctype html> 
<html> 
   <head> 
      <meta charset="utf-8"> 
      <title>WebAssembly Add Function</title>
      <style>
         div { 
            font-size : 30px; text-align : center; color:orange; 
         } 
      </style>
   </head>
   <body>
      <div id="textcontent"></div>
      <script> 
         fetch("firstprog.wasm")
         .then(bytes => bytes.arrayBuffer())
         .then(mod => WebAssembly.compile(mod))
         .then(module => {return new WebAssembly.Instance(module)})
         .then(instance => {   
            console.log(instance); 
            let buffer = new Uint8Array(instance.exports.memory.buffer); 
            let test = instance.exports.c_hello(); 
            let mytext = ""; 
            for (let i=test; buffer[i]; i++) {
               mytext += String.fromCharCode(buffer[i]);
            }
            console.log(mytext); document.getElementById("textcontent").innerHTML = mytext; 
         });
      </script>
   </body>
</html>

我们添加了一个 div,并将内容添加到该 div 中,因此字符串将显示在浏览器上。

输出

输出如下所示:

Hello World
广告