webassembly介绍

本文介绍Webassembly的基本应用和接入方法,初步认识Webassembly技术

一、WebAssembly介绍

1、什么是WebAssembly

WebAssembly/wasm 是一个可移植、体积小、加载快并且兼容 Web 的全新二进制格式,其目标就是充分发挥硬件能力以达到原生执行效率。是一种可以使用非Javascript的编程语言编写代码并且能在浏览器上运行的技术方案,实际上,是一种新的字节码格式。

官方介绍:https://www.wasm.com.cn/

2019年12月5日,WebAssembly正式成为World Wide Web Consortium (W3C)的标准,加入到HTML、CSS、JavaScript的行列,成为web的第四种语言。

可以打开浏览器控制台输入WebAssembly查看。

浏览器兼容性:https://caniuse.com/?search=WebAssembly

2、WebAssembly的应用

https://www.wasm.com.cn/docs/use-cases/

前端应用场景:

1、figma:https://www.figma.com/file/Q6UiKr10qxMrStOLznhCn4/%E7%BA%BF%E4%B8%8B%E6%B4%BB%E5%8A%A8%E5%BC%95%E6%B5%81%2F%E8%AE%BE%E8%AE%A1%E8%B5%B0%E6%9F%A5?node-id=0%3A1

2、google地图:https://earth.google.com/static/wasm/

3、坦克大战:https://unity3d.com/learn/tutorials/projects/tanks-tutorial

4、微信小程序:https://developers.weixin.qq.com/miniprogram/dev/framework/performance/wasm.html

非*前端应用场景:

1、Fastly 与其他服务商的边缘云(参见[译][图文]标准化中的 WASI:在 web 之外运行 WebAssembly 的系统接口)

2、Node 与 npm(参见译文)插件系统。无论浏览器、IDE 还是任何其他地方的插件系统如果采用 WebAssembly 既能保证安全性避免插件代码越权,也能与开发语言解耦、有利于插件生态的繁荣。

3、Docker 的联合创始人Solomon Hykes 甚至说,如果在 2008 年有 WebAssembly + WASI(WebAssembly System Interface, WASM系统接口),就无需创建 Docker 了。

其他应用:https://blog.csdn.net/vhwfr2u02q/article/details/79235198

3、WebAssembly的优势

  • 文件加载:WebAssembly文件体积更小,所以下载速度更快
  • 解析:解码WebAssembly比解析JavaScript要快
  • 编译和优化:编译和优化所需的时间较少,因为在将文件推送到服务器之前已经进行了更多优化,JavaScript需要为动态类型多次编译代码
  • 重新优化:WebAssembly代码不需要重新优化,因为编译器有足够的信息可以在第一次运行时获得正确的代码
  • 执行:执行可以更快,WebAssembly指令更接近机器码
  • 垃圾回收:目前WebAssembly不直接支持垃圾回攻,垃圾回收都是手动控制的,所以比自动垃圾回收效率更高
  • 安全:可以放hash和签名等等

二、WebAssembly工作原理

1、官方解读

WebAssembly是除了JavaScript以外,另一种可以在网页中运行的编程语言。过去如果你想在浏览器中运行代码来对网页中各种元素进行控制,只有JavaScript这一种选择。

WebAssembly与其他的汇编语言不一样,它不依赖于具体的物理机器。可以抽象地理解成它是概念机器的机器语言。

它可以从各类现有的其他高级语言写的业务库编译而来,还有Haskell、Go、C#、Rust、swift、obj-C的语言的一些WebAssembly编译工具或者已经编译成的WebAssembly代码库。

既然是经过编译而得来,可以将WebAssembly理解为是该库的低级语言代码版本,是一种类汇编语言。

可以把它理解成一个ES6语法写的js模块,既可以有导入又有导出,也可以没有导入只有导出。

2、两类文件

WebAssembly文件格式与源码阅读->.wasm文件和.wast文件

WebAssembly代码存储在.wasm文件内,这类文件是要浏览器直接执行的。 因为.wasm文件内是二进制文件,难以阅读,为了方便开发者查看,官方给出了对.wasm文件的阅读方法, 通过把.wasm文件通过工具转为.wast的文本格式,开发者可以在一定程度上理解这个.wast文件。 .wast文件是通过S-表达式(一种类似lisp语言(函数式程序设计)的代码书写风格)来写成的。 .wast文件和.wasm文件的关系,他们之间的相互转化,可以通过工具wabt(https://github.com/WebAssembly/wabt)

3、工作流程

image.png

某高级语言写的某功能库–>emscripten编译–>.wasm文件–>结合WebAssembly JS API–>浏览器中运行 完成一部分 用js写,而后依靠浏览器解释执行,会比较消耗性能 的工作,比如视频解码,OpenGL,OpenCV等。 简单来说,加载运行wasm代码的过程如下图所示。

image.png

详细的过程以及每个过程调用的API如下图。

image.png

三、运行WebAssembly

1、WebAssembly工具

中文官方介绍:https://www.wasm.com.cn/getting-started/developers-guide/

Emscripten工具:https://emscripten.org/docs/getting_started/downloads.html

在线转换工具:https://mbebenita.github.io/WasmExplorer/

2、WebAssembly API

image.png

WebAssembly.Mudule和WebAssembly.compile()

都是用来把一个wasm的arraybuffer对象编译成一个模块,前者是同步的,后者是异步的,后者使用更多。 前者使用方式:new WebAssembly.Mudule(buffer);后者使用方式:WebAssembly.compile(buffer); WebAssembly.Mudule本身也是抽象意义上的模块对象。这两种方式调用以后,返回值都是一个模块对象,该对象 有导入对象、导出对象和自定义片段(custom section)。

WebAssembly.Instance和WebAssembly.instantiate()

都是用来做实例化,前者是同步的,后者是异步的,后者使用更多。 前者使用方式:new WebAssembly.Instance();后者使用方式:WebAssembly.instantiate(); 前者有两个重载,一个是传入buffer和imports对象,这种调用一次性完成了编译和实例化两个步骤, 第二个重载是传模块对象和imports对象,这种调用只完成实例化步骤。 因此,实际上WebAssembly.instantiate()和WebAssembly.Instance的第二张重载调用功能上更接近。

3、示例

1、首先新建一个 C 语言文件,假设叫 math.c ,在里边实现 add 和 square 方法:

int add (int x, int y) {
  return x + y;
}

int square (int x) {
  return x * x;
}

2、生成wasm文件

emcc math.c -Os -s WASM=1 -s SIDE_MODULE=1 -o math.wasm

在线编译:https://mbebenita.github.io/WasmExplorer/

3、前端工程加载wasm文件

/**
   * @param {String} path wasm 文件路径
   * @param {Object} imports 传递到 wasm 代码中的变量
   */
  function loadWebAssembly(path, imports: any = {}) {
    return fetch(path)
      .then((response) => response.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: any) => {
    console.log('instance', instance);
    const { add, square } = instance.exports;
    console.log('2 + 4 =', add(2, 4));
    console.log('3^2 =', square(3));
    console.log('(2 + 5)^2 =', square(add(2 + 5)));
  });

4、window执行C/C++与js执行对比

js 斐波那契算法:

 

/**
   * 斐波那契函数
   * 0 1 1 2 3 5 8 ...
   * @param x
   */
  function fib (x) {
    if(x <= 0) return 0;
    if(x <= 2) return 1;
    return fib(x - 1) + fib(x - 2);
  }

  console.time('测试 fib 执行速度');
  fib(40);
  console.timeEnd('测试 fib 执行速度');
  // 测试 fib 执行速度: 751.1669921875 ms

c++斐波那契算法:

#include <iostream>
#include <ctime>

using namespace std;

int fib(int x)
{
    if(x <= 0) return 0;
    if(x <= 2) return 1;
    return fib(x - 1) + fib(x - 2);
}

int main ()
{
    int t1, t2;
    t1 = clock();
    fib(40);
    t2 = clock();
    cout << t2 - t1 << "ms" << endl;
    return 0;
}

安装C++编译器:https://blog.csdn.net/cbb944131226/article/details/82940273

执行

 

g++ fib.cpp -o c
// g++ fib.cpp -o c -O4
c.exe
// 396ms

 

编译fib函数 得到fib.wasm,浏览器加载加载fib.wasm

loadWebAssembly('fib.wasm').then((instance: any) => {
    console.log('fib.instance', instance);
    const { fib } = instance.exports;
    console.time('测试 C++ fib 执行速度');
    fib(40);
    console.timeEnd('测试 C++ fib 执行速度');
  });
 // 测试 C++ fib 执行速度: 564.48681640625 ms

相关资源推荐:

(1)英文官网 http://webassembly.org/

(2)中文官网 http://webassembly.org.cn/

(3)MDN网址 https://developer.mozilla.org/zh-CN/docs/WebAssembly

(4)资料齐全 https://github.com/mbasso/awesome-wasm

(5)一篇文章 https://segmentfault.com/a/1190000008402872

(6)一篇文章 https://segmentfault.com/a/1190000008686643

(7)有编译工具链简单介绍 http://geek.csdn.net/news/detail/185592

posted @ 2022-07-04 14:32  Peter_Yang0942  阅读(1255)  评论(0编辑  收藏  举报