WebAssembly - “你好世界”


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

将使用 wasm 资源管理器工具将 C 程序转换为 .wasm 并在我们的 .html 文件中使用 .wasm。

https://mbebenita.github.io/WasmExplorer/上提供的 Wasm 浏览器工具如下所示 -

C代码

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

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

使用 C 代码更新 wasm 资源管理器中的第一个块,如下所示 -

更新第一个块

单击 COMPILE 按钮编译为 WASM 和 WAT 以及 Firefox x86 Web Assembly,如下所示 -

编译

使用下载获取 .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步

.wasm 代码必须使用ArrayBuffer转换为 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

要获取模块,我们必须调用 web assembly.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 详细信息如下所示 -

控制台日志

为了从函数 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();

现在,测试变量有了读取字符串的起点。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中,因此字符串显示在浏览器上。

输出

输出如下 -

你好世界