webAssembly简介

Posted 前端配送站

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webAssembly简介相关的知识,希望对你有一定的参考价值。

在前端领域还处于战火纷飞却又百家争鸣的年代,相关的技术风起云涌,各成一派,类似我这样的看客,在经历着这些知识的洗礼之时,不免想搬一下砖,所以就有了这篇介绍webAssembly的文章。

1 起因

针对js语言自身的原因(语法灵活,性能),近来出现了一些js的变种,例如:ts、asm等,但是这些变种也都有自己的缺陷(eg:ts只解决语法灵活,并未对性能做优化),这个时候就一种发声,那就是webAssembly,它主张创造一种新的字节码格式。

2 经过

2.1 overview

WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.

相对于 JS,WebAssembly 有如下优点:

  • 体积小:由于浏览器运行时只加载编译成的字节码,一样的逻辑比用字符串描述的 JS 文件体积要小很多;

  • 加载快:由于文件体积小,再加上无需解释执行,WebAssembly 能更快的加载并实例化,减少运行前的等待时间;

  • 兼容性问题少:WebAssembly 是非常底层的字节码规范,制订好后很少变动,就算以后发生变化,也只需在从高级语言编译成字节码过程中做兼容。可能出现兼容性问题的地方在于 JS 和 WebAssembly 桥接的 JS 接口。

快速体验:在控制台输入以下代码就可体验

WebAssembly.compile(new Uint8Array(`  
 00 61 73 6d   01 00 00 00   01 0c 02 60   02 7f 7f 01
  7f 60 01 7f   01 7f 03 03   02 00 01 07   10 02 03 61  
  64 64 00 00   06 73 71 75   61 72 65 00   01 0a 13 02  
  08 00 20 00   20 01 6a 0f   0b 08 00 20   00 20 00 6c  
  0f 0b`
.trim().split(/[\s\r\n]+/g).map(str => parseInt(str, 16))
 )).then(module => {  
   const instance = new WebAssembly.Instance(module)
   //使用 WebAssembly.Instance 将模块对象转成 WebAssembly 实例  
   const { add, square } = instance.exports
   //通过 instance.exports 可以拿到 wasm 代码输出的接口  
   console.log('2 + 4 =', add(24))  
   console.log('3^2 =', square(3))  
   console.log('(2 + 5)^2 =', square(add(2 + 5)))
})

ps:官网上说火狐、IE、Safari、chrome这四个浏览器已经支持webassembly1.0

Chrome: 

打开chrome://flags/#enable-webassembly,选择enable。

2.2 hello world

1 .wasm文件长啥样?

sample.wasm

0061 736d 0100 0000 0107 0160 027f 7f01
7f03 0201 0007 0701 0361 6464 0000 0a09
0107 0020 0020 0160b

2 全是二进制码,看不懂怎么办?

wabt工具!

https://github.com/webassembly/wabt该工具可以把wasm文件和wat文件相互转换

按照步骤各种装完之后(long  time…),执行命令

$wasm2wat sample.wasm -o sample.wat

.wat文件长啥样?

sample.wat

(module
  (func $add (param $lhs i32) (param $rhs i32) (result i32)
    get_local $lhs    
    get_local $rhs    
    i32.add)  
  (export "add" (func $add))
)

3 如何在js中使用?

大致逻辑:

For basic loading, there are three steps:

  1. Get the .wasm bytes into a typed array or ArrayBuffer

  2. Compile the bytes into a WebAssembly.Module

  3. Instantiate the WebAssembly.Module with imports to get the callable exports

具体实现:

WebAssembly.instantiateStreaming(fetch('sample.wasm'))
.then(obj => {   
 console.log(obj.instance.exports.add(12));  // "3"
});

4:webAssembly也支持模块化的导入导出

module.wat

(module
  (func $i (import "imports" "imported_func") (param i32))  
 (func (export "exported_func")
     i32.const 42    
     call $i))

js

var importObject = {    
 imports: {      
   imported_funcfunction(arg{        
     console.log(arg);      
   }    
 }  
};  
fetch('simple.wasm').then(response =>    
 response.arrayBuffer()  
).then(bytes =>    
 WebAssembly.instantiate(bytes, importObject)  
).then(result =>    
 result.instance.exports.exported_func()  
);

5 WebAssembly的底层内存模型、WebAssembly.Table()等等

2.3 用什么编写webAssembly?+怎样生成.wasm文件?

首先呢?用什么语言coding?在对webAssembly进行介绍的时候引用了一段官网的话,其实人家对自己产品的定位是很高的呢

Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.

下面就简单介绍一下用ts和C/C++编写代码,生成.wasm文件的过程

2.3.1 ts -> wasm

安装:

https://github.com/AssemblyScript/assemblyscript#installation

用 TypeScript 实现斐波那契序列计算的模块如下: f.ts

export function f(x: i32): i32 {    
 if (x === 1 || x === 2) {        
   return 1;    
 }    
 return f(x - 1) + f(x - 2)
}

run: asc f.ts -o f.wasm     //把代码编译成可运行的WebAssembly 模块

js加载调用:

fetch('f.wasm'// 网络加载 f.wasm 文件    
 .then(res => res.arrayBuffer()) // 转成 ArrayBuffer    
 .then(WebAssembly.instantiate) // 编译为当前 CPU 架构的机器码 + 实例化    
 .then(mod => { // 调用模块实例上的 f 函数计算    
 console.log(mod.instance.f(50));    
});

2.3.2 c/c++ -> wasm

安装:https://github.com/juj/emsdk

hello.c

#include <stdio.h>
int main(int argc, char ** argv) {  
 printf("Hello World\n");  
 return 0;
}
emcc hello.c -s WASM=1 -o hello.html

ps:编译后会自动有一个hello.js

2.4 扩展

  • 可接入webpack

  • WebAssembly调JS

  • 直接执行wasm二进制文件

3 结果

目前WebAssembly的发展尚不成熟,但是它有自身的一些优势,能够解决一些性能问题,所以也有自己的立足之地。

WebAssembly 更适合用于写模块,承接各种复杂的计算,如图像处理、3D运算、语音识别、视音频编码解码这种工作,主体程序还是要用 javascript 来写的。。

本文参考:

  • WebAssembly 现状与实战

    https://www.ibm.com/developerworks/cn/web/wa-lo-webassembly-status-and-reality/index.html

  • MDN

    https://developer.mozilla.org/zh-CN/docs/WebAssembly/Using_the_JavaScript_API

  • webassembly官网

    https://webassembly.org/getting-started/developers-guide/

  • WebAssembly详解及其使用案例https://cloud.tencent.com/developer/article/1089927


以上是关于webAssembly简介的主要内容,如果未能解决你的问题,请参考以下文章

webAssembly简介

图书深入浅出WebAssembly

Docker 学习总结(78)—— WebAssembly 入门简介

Docker 学习总结(78)—— WebAssembly 入门简介

Docker 学习总结(78)—— WebAssembly 入门简介

指向本地结构的指针如何转换为 webassembly?