wasm 现状
  • 目前主要应用在对性能要求较高的应用中、VR、游戏等
  • 从前端角度来看,并没有广泛使用,但各大厂对wasm比较积极,相信不远的将来wasm将得以广泛应用,
    • 因此学一门后端语言非常重要,C/C++/go/python,建议学习python或go,python较其他语言较容易入门,不过本人更倾向go,不想干前端了就去做后端~
  • wasm体验
wasm 特点
  • 标准
    • WebAssembly 在 web 中被设计成无版本、特性可测试、向后兼容,
    • wasm可以被js调用,进入js上下文,也可以像Web API 一样调用浏览器功能
    • wasm即可以运行在浏览器也可以诶运行在非web环境
  • 高效
    • WebAssembly 有一套完整的语义,wasm 是体积小且加载快的二进制格式,其目标就是充分发挥硬件能力已达到原生的执行效率
  • 安全
    • wasm 运行在一个沙箱化的执行环境中,甚至可以在现有的js虚拟机中实现
    • 在web环境中,wasm 严格遵守同源策略和浏览器安全策略
  • 开放
    • wasm 设计了一个非常规整的文本格式,可以以这种文本格式在web页面上查看wasm模块的源码

WebAssembly 初探_WebAssembly

wasm 作为一个模块在web环境下运行(wasm在V8引擎中得以实现),也可以运行在服务端环境

wasm vs js

WebAssembly 初探_WebAssembly_02

  • wasm 在开发过程中就将 Parse 前置了
  • wasm 没有GC,wasm GC与V8 GC 不是一回事,它有独立的内存空间,由代码进行管理,因此开发要注意内存问题
性能问题

例如:递归Fibonacci 函数,wasm vs js WebAssembly 初探_WebAssembly_03

wasm 开发工具

环境准备

  • 安装 gcc 编译环境
  • 安装 g++ 编译环境
  • 安装 xcode
  • 安装 cmake
  • emscripten:wasm 的灵魂工具,将其他高级语言编译成 wasm,针对后端语言
  • AssemblyScript: 支持直接将 Typescript 编译成 wasm。类似ts语法,但它可不是typescript,不建议使用(可选)
  • WABT: 将wasm在字节码和文本格式相互转换的一个工具,方便开发时理解wasm底层(可选)
Javascript API
  • 方法

--  WebAssembly.compile() 将 wasm 编译成 v8可以执行的代码 --  WebAssembly.instantiate() 实例化 --  WebAssembly.validate() 验证包含 wasm 二进制码的一个 typed array 是否合法

    • WebAssembly.Module 模块
    • WebAssembly.Instance 实例
    • WebAssembly.Memory 内存空间
    • WebAssembly.Table 是JavaScript包装器对象-一种表示WebAssembly表的类似数组的结构,该表存储函数引用。由JavaScript或WebAssembly代码创建的表将可以从JavaScript和WebAssembly访问并可变
    • WebAssembly.CompileError 编译时错误
    • WebAssembly.LinkError 实例化时错误
    • WebAssembly.RuntimeError 运行时错误
C 编写 wasm

实现一个 Hello world

/**
 * 编译可执行文件
 * gcc hello.c -o hello
 * 执行可执行程序
 * ./hello
 * 输出 hello world!
 *//**
 * 编译成wasm
 * emcc hello.c -o hello.js,生成 hello.js 和 hello.wasm
 * 执行wasm
 * node hello.js
 * 输出 hello world!
 */#include <stdio.h> // 引入标准输入输出库int main(){  printf("hello world!\n");  return 0;
}复制代码

生成可在浏览器中运行的 wasm

/**
 * 编译命令 按照wasm的模式以模块的形式输出 math.wasm
 * emcc math.c -Os -s WASM=1 -s SIDE_MODULE=1 -o math.wasm
 */int add(int x, int y){  return x + y;
}int square(int x){  return x * x;
}复制代码

创建 index.html 页面在浏览器中调用 wasm对象

<!DOCTYPE html><html lang="en"><head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title></head><body>
  <script>/**
      * @param {String} path wasm 文件路径
      * @param {Object} imports 传递到 wasm 代码中的变量
    */function loadWebAssembly(path, imports = {}) {      return fetch(path) // 加载文件.then(response => response.arrayBuffer()) // 转成 ArrayBuffer.then(buffer => WebAssembly.compile(buffer))
        .then(module => {
          imports.env = imports.env || {}          // 开辟内存空间  imports.env.memoryBase = imports.env.memoryBase || 0  if (!imports.env.memory) {
            imports.env.memory = new WebAssembly.Memory({ initial: 256 })
          }          // 创建变量映射表  imports.env.tableBase = imports.env.tableBase || 0  if (!imports.env.table) {// 在 MVP 版本中 element 只能是 "anyfunc"imports.env.table = new WebAssembly.Table({ initial: 0, element: 'anyfunc' })
          }          // 创建 WebAssembly 实例  return new WebAssembly.Instance(module, imports)
    }//调用loadWebAssembly('./math.wasm')
      .then(instance => {const add = instance.exports.add //取出c里面的方法const square = instance.exports.square //取出c里面的方法console.log('10 + 20 =', add(10, 20))console.log('3*3 =', square(3))console.log('(2 + 5)*2 =', square(add(2 + 5)))
      })  </script></body></html>复制代码

控制台输出:

WebAssembly 初探_WebAssembly_04