什么是WebAssembly
| web前端
评论 0 | 点赞 0 | 浏览 882

什么是wasm文件?

在使用浏览器控制台network的时候,有时会出现这样的请求:

没错,请求一个后缀名未wasm的文件,从控制台source中打开查看这个文件,发现这个文件看起来类似汇编一样的代码:

其实,这是通过WebAssembly技术生成的文件,本文介绍WebAssembly是什么。

什么是WebAssembly?

WebAssembly是一种可以将C/C++、Rust等高级语言编译成浏览器可执行的二进制文件的技术,他弥补了JavaScript性能低的缺点。可以说,WebAssembly技术出现的核心宗旨就是为了提升web应用程序的性能

JavaScript的执行过程

js代码的执行依赖js引擎,其执行过程大概分成以下几个阶段:

1、词法分析

这一步,程序员编写的代码会被分解成多个词法单元,词法单元包括关键字(如 function 、var )、标识符(如变量名和函数名)和操作符(如 + 、-、* 、/ 等)等。

举例,先写一个简单的js函数:

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

这个函数被分解成词法单元后是下面这个样子:

Keyword 'function'
Identifier 'add'
Punctuator '('
Identifier 'x'
Punctuator ','
Identifier 'y'
Punctuator ')'
Punctuator '{'
Keyword 'return'
Identifier 'x'
Punctuator '+'
Identifier 'y'
Punctuator ';'
Punctuator '}'

2、语法分析

这一步,词法单元会被转化成抽象语法树(AST),通过树形结构表示js语法结构

举例,上面的函数生成的AST如下所示:

{
  "type": "FunctionDeclaration",
  "id": {
    "type": "Identifier",
    "name": "add"
  },
  "params": [
    {
      "type": "Identifier",
      "name": "x"
    },
    {
      "type": "Identifier",
      "name": "y"
    }
  ],
  "body": {
    "type": "BlockStatement",
    "body": [
      {
        "type": "ReturnStatement",
        "argument": {
          "type": "BinaryExpression",
          "operator": "+",
          "left": {
            "type": "Identifier",
            "name": "x"
          },
          "right": {
            "type": "Identifier",
            "name": "y"
          }
        }
      }
    ]
  }
}

3、使用翻译器,将代码转化为字节码

4、使用字节码解释器,将字节码转化为机器码,最终运行的是机器码

为了提高运行速度,现代浏览器一般采用即时编译(JIT-Just In Time compiler),即字节码只在运行时编译,用到哪一行就编译哪一行,并且把编译结果缓存(inline cache);且js是有GC的,有GC就意味着在垃圾回收的时候会出现阻塞等待。js的这一系列特性决定了他难以完成高性能计算场景,例如游戏渲染、音视频渲染等。

但是许多厂商为web应用的性能提升做了许多努力,最具代表性的就是Adobe Flash Player和谷歌V8引擎。

提起Adobe Flash Player很多人的印象都很差,早期很多视频网站没有flash会无法播放,4399网站的许多小游戏也依赖flash,同时flash插件本身还有不少的广告;实际上,flash插件的最初设计目的为播放二维向量动画,后来被大量运用到网页游戏、动画中。乔布斯曾公开声明,永远不支持Adobe Flash,引发了Flash插件时代的终结。

谷歌V8引擎,算是一个重大的性能提升了,他跳过了生成字节码的过程,直接生成机器码。

WebAssembly的诞生

2015年,4个浏览器产商(Firefox, Chrome, Safari, Edge)达成合作,4个竞争者宣布联手开发WebAssembly。

2019年,W3C发布WebAssembly正式标准,WebAssembly成为继HTML、CSS、JavaScript之后第4种Web语言。

WebAssembly实际上属于一种编程语言,只不过他是二进制的,虽然提供了可以阅读的文本格式,但是依旧难以编写,直接编写WebAssembly文件等同于你在9102年的今天手写汇编,因此目前的WebAssembly文件都是通过C/C++等高级语言编译成的。值得注意的是,WebAssembly并不等同于机器码,他是一种低级二进制格式,也需要编译成机器可执行的机器码,只不过相比js的解析,它的编译过程更快更简单此外,此解码/编译步骤可以跨多个线程拆分,并且整个过程在模块仍在下载时开始。这大大减少了下载应用程序代码和达到峰值执行速度所需的时间。

但是WebAssembly并不能直接访问浏览器的API,例如DOM、WebGL、WebAudio等,他必须通过JavaScript代码来访问。

目前大部分浏览器都支持WebAssembly,开发人员可以在js代码中通过浏览器提供的API来调用WebAssembly函数,反之,WebAssembly也可以通过浏览器API调用js函数。

WebAssembly的应用

WebAssembly一般应用在需要高性能计算的场景上。目前部分web程序已经使用了这项技术,例如Google Earth(https://earth.google.com/web/

WebAssembly的实际使用教程(Java版本)

事先声明,在写这篇博文的时候我虽然做过诸多尝试,但仍然没有成功将java代码转成WebAssembly,后来我放弃了,因为我觉得没有意义,WebAssembly是为了追求高性能而诞生的,所以理论上,应该选择从C/C++来编译,事实也确实如此,我找了一下java中和WebAssembly相关的生态,少的可怜,而且很不成熟,下面我介绍两个:

1、TeaVM,这是一个可以将jvm字节码文件编译成WebAssembly的编译器,只要是jvm字节码都可以,所以语言上可以选择java、scala、Kotlin等。这个是github地址:https://github.com/konsoletyper/teavm,官网文档地址:https://mirkosertic.github.io/Bytecoder/chapter-1/page-1-c/,文档简直依托答辩,不知道是哪个大聪明写的,看不懂好吧。

2、JWebAssembly,这是一个将java代码转成WebAssembly的库,github地址:https://github.com/i-net-software/JWebAssembly,文档地址:https://github.com/i-net-software/JWebAssembly/wiki,这个的文档写的比较好,容易懂,但是对maven的支持并不好,本人试了一遍并没有成功,各位读者可以尝试通过gradle打包。

无论通过什么方式编译WebAssembly,最后都会生成一个wasm文件,这个文件就是我们要的。下面介绍怎么在js代码中调用wasm。

浏览器提供了相关的API可以直接调用

fetch('example.wasm')  //wasm文件path
  .then(response => response.arrayBuffer()) //转成buffer数组
  .then(bytes => WebAssembly.instantiate(bytes)) 
  .then(module => {
    const wasmFunc = module.instance.exports.myFunction;
    const result = wasmFunc(1, 2); // 调用wasm中的函数,并传递参数    console.log(result); // 打印wasm函数返回的结果
  });

这里有个demo可以看一下:https://i-net-software.github.io/JWebAssembly/samples/HelloWorld/HelloWorld.html,在浏览器控制台查看source

拓展阅读

推荐阅读一下这篇文章,对于直播类业务可提供参考价值:爱奇艺直播WebAssembly优化之路

本文作者:不是好驴
本文链接:https://www.baddonkey.cn/detail/46
版权声明:原创文章,允许转载,转载请注明出处

高谈阔论

留言列表