理解 Wasm 基础概念,了解 Wasm 是如何被加载运行的?

大家好,我是前端西瓜哥,这次带大家来简单系统学习一下 wasm(WebAssembly)。

成都创新互联是专业的加查网站建设公司,加查接单;提供成都网站制作、做网站,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行加查网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!

示例源码在这个 github 仓库,可自行下载运行:

https://github.com/F-star/wasm-demo。

wasm 是如何被加载运行的?

wasm 文件本身并不能像 JavaScript 一样,下载完成后就立即执行。

它更类似于 webgl 编译着色器代码,需要调用 JavaScript 提供的 API 去编译执行。

wasm 被加载并执行的过程一般为:

  • 请求 wasm 文件。
  • 转换为 ArrayBuffer 格式(也就是字节数组)。
  • 编译并返回 Module 对象(异步的,可使用阻塞写法)。
  • 基于 Module 创建一个 instance 实例(异步的,可使用阻塞写法) 。instance 的 exports 对象下为 wasm 暴露出来的方法和属性。创建 instance 有时需要提供一个额外的 importObject 对象,后文再细说。
  • 执行 JavaScript 代码,调用 wasm 的方法,进行数据的交换。

代码实例:

fetch('./add.wasm')
  .then(rep => rep.arrayBuffer()) // 转 ArrayBuffer
  .then(bytes => WebAssembly.compile(bytes)) // 编译为 module 对象
  .then(module => WebAssembly.instantiate(module)) // 创建 instance 对象
  .then(instance => {
   // 拿到 wasm 文件暴露的 add 方法
    const { add } = instance.exports;
    console.log(add(12, 34));
  });

上面是为了让大家理解所有步骤,所以写得很繁琐。

我们有简单写法,用一个 API 把步骤 1、2、3、4 组合在一起:

WebAssembly.instantiateStreaming(fetch('./add.wasm')).then(res => {
  const { module, instance } = res;
  const { add } = instance.exports;
  console.log(add(12, 34));
});

WebAssembly.instantiateStreaming 支持流式编译,在 wasm 文件下载过程中就开始编译了,并最后会一次性返回编译和实例化产生的 module 和 instance 对象。

wasm 目前现在无法像 ES Module 一样,通过 import 的方式直接被引入(