WebAssembly概念
webassembly是一种运行在现代web浏览器中的新型代码,不仅提供新的性能特性,同时还在性能方面有着巨大提升。它的涉及本意并非是提供开发者直接编译的代码,而是为诸如C,C++和Rust等源语言提供的一个有效的编译目标。
简单来说,你可以使用C,C++,Rust,Go等语言编写代码,然后编译为WebAssembly,在浏览器中运行。
编译C/C++为WebAssembly
Emscripten环境安装
所需条件
- python
- git
安装步骤
- 打开cmd,进入到软件将会安装到的目录下
- 输入 git clone https://github.com/emscripten-core/emsdk.git
- 输入 cd emsdk
- 输入 emsdk install latest
- 配置系统环境变量,依据下图操作

打开编译系统环境变量窗口,点击环境变量



最后一直点击每个未关闭窗口的确认即可。
具体使用
使用cmd打开需要被编译的C++文件夹,输入命令行emsdk activate (这仅仅会激活当前的环境,下次换另一个文件夹还需要再次激活),输入命令行emcc -v来检测配置是否成功,配置成功即可进入文件中书写代码。
代码编写完成后进入cmd窗口,输入命令行emcc 文件名 ,编译器就会对该文件进行编译.

当我们查看文件夹时,会发现多出来两个文件,一个是wasm格式的文件,一个是js格式的文件,前者是二进制文件,可以wasm2wat中打开该文件,后者放在html当中引入即可发现文件顺利转换且生效.
调用一个在C中的自定义方法
1.在文件夹下创建streaming文件夹,创建streaming.c文件,编写c语言代码
c
#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE
int sumOfNInts(int n)
{
// return n*(n+1)/2;
return my_div(mul(n,add(n,1)),2);
}
2.打开对应代码文件的cmd窗口,然后输入emcc streaming.c -o streaming.js

3.输入命令之后的效果如图所示

4.在html页面中调用c语言函数
- 实例化wasm模块
- 创建全局变量存储exports
- 使用exports来调用C语言函数
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>你好,WebAssembly!</p>
<input type="number" id="a">
<button onclick="run_wasm()">trigger触发</button>
<p id="res"></p>
</body>
<script>
// 创建变量来存储exports,使得可以全局访问
let exports
// 实例化wasm模块
WebAssembly.instantiateStreaming(
fetch("streaming.wasm"),{}
).then(result => exports = result.instance.exports);
function run_wasm(){
let a = document.querySelector('#a').value;
// 使用exports调用c语言函数
let sum = exports.sumOfNInts(a);
document.querySelector("#res")
.innerHTML += `${a} => ${sum}<br/>`;
}
</script>
</html>
内存模型
1.使用js来操作wasm内存
- 初始化内存(设置内存大小,以及内存最大扩容量)
- 创造视图
- 使用typearray, 使用new关键字构造Uint32Array,不同类型数据需要使用不同的typearray,如数字类型数据需要使用Uint32Array,字符串类型需要使用Uint8Array;
- typearray(buffer:any,byteOffset?:number,length?:number)
- buffer指的是内存本身,byteOffset是偏移量,length是所需内存长度
- 通过视图操作内存
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>你好,WebAssembly!</p>
<input type="number" id="a">
<button onclick="run_wasm()">trigger触发</button>
<button onclick="getStr()">获取字符串</button>
<p id="res"></p>
</body>
<script>
let memeory = new WebAssembly.Memory({
initial:256,
maximum:512
})
// 创建变量来存储exports,使得可以全局访问
let exports
WebAssembly.instantiateStreaming(
fetch("memory.wasm"),{
js:{
mem:memeory
}
}
).then(result =>{
exports = result.instance.exports;
memory = result.instance.exports.memory;
});
function run_wasm(){
let arr = new Uint32Array(memory.buffer);
for(let i =0;i<10;i++){
arr[i] = i*2;
}
let sum = exports.accumulate(0,10);
document.querySelector("#res")
.innerHTML += `${sum}<br>`;
}
</script>
</html>
2.使用c语言来向内存中写入数据,然后js来调用c语言函数读取内存
c
#include <emscripten.h>
int main()
{
return 0;
}
EMSCRIPTEN_KEEPALIVE
const char *getString()
{
return "Hello,WebAssembly!"
}
javascript
let memory = new WebAssembly.Memory({
initial:256,
maximum:512
})
let exports;
WebAssembly.instantiateStreaming(
fetch("memory.wasm"),{
js:{
mem:memory
}
}
).then(result => {
exports = result.instance.exports;
memory = result.instance.exports.memory;
})
function getStr(){
let ptr = exports.getString();
let bytes = new Uint8Array(exports.buffer,ptr);
let strlen = 0;
while(bytes[strlen]){strlen++};
let str = new TextDecoder("utf8").decode(
bytes.slice(0,strlen)
)
console.log(str);
}