这篇文章打算讲什么?

了解 WebAssembly 的前世今生,这一致力于让 Web 更广泛使用的伟大创造是如何在整个 Web/Node.js 的生命周期起作用的,探讨为什么 WASM 是 Web 的未来?

在整篇文章的讲解过程中,你可以了解到 WebAssembly 原生、AssemblyScript、Emscripten 编译器。

最后还对 WebAssembly 的未来进行了展望,列举了一些令人兴奋的技术的发展方向。

我在之前也撰写过深入了解 WebAssembly 使用细节和在浏览器里面调试 WebAssembly 代码的文章,感兴趣的同学可以点击链接阅读:

  • WebAssembly 在浏览器中调试
  • 编译 C/C++ 程序到WebAssembly,然后运行在浏览器和 Node.js

为什么需要 WebAssembly ?

动态语言之踵

首先先来看一下 JS 代码的执行过程:

上述是 Microsoft Edge 之前的 ChakraCore 引擎结构,目前 Microsoft Edge 的 JS 引擎已经切换为 V8 。

整体的流程就是:

  • 拿到了 JS 源代码,交给 Parser,生成 AST
  • ByteCode Compiler 将 AST 编译为字节码(ByteCode)
  • ByteCode 进入翻译器,翻译器将字节码一行一行翻译(Interpreter)为机器码(Machine Code),然后执行

但其实我们平时写的代码有很多可以优化的地方,如多次执行同一个函数,那么可以将这个函数生成的 Machine Code 标记可优化,然后打包送到 JIT Compiler(Just-In-Time),下次再执行这个函数的时候,就不需要经过 Parser-Compiler-Interpreter 这个过程,可以直接执行这份准备好的 Machine Code,大大提高的代码的执行效率。

但是上述的 JIT 优化只能针对静态类型的变量,如我们要优化的函数,它只有两个参数,每个参数的类型是确定的,而 JavaScript 却是一门动态类型的语言,这也意味着,函数在执行过程中,可能类型会动态变化,参数可能变成三个,第一个参数的类型可能从对象变为数组,这就会导致 JIT 失效,需要重新进行 Parser-Compiler-Interpreter-Execuation,而 Parser-Compiler 这两步是整个代码执行过程中最耗费时间的两步,这也是为什么 JavaScript 语言背景下,Web 无法执行一些高性能应用,如大型游戏、视频剪辑等。

静态语言优化

通过上面的说明了解到,其实 JS 执行慢的一个主要原因是因为其动态语言的特性,导致 JIT 失效,所以如果我们能够为 JS 引入静态特性,那么可以保持有效的 JIT,势必会加快 JS 的执行速度,这个时候 asm.js 出现了。

asm.js 只提供两种数据类型:

  • 32 位带符号整数
  • 64 位带符号浮点数

其他类似如字符串、布尔值或对象都是以数值的形式保存在内存中,通过 TypedArray 调用。整数和浮点数表示如下:

ArrayBuffer对象、TypedArray视图和DataView 视图是 JavaScript 操作二进制数据的一个接口,以数组的语法处理二进制数据,统称为二进制数组。参考 ArrayBuffer 。

var a = 1;var x = a | 0;  // x 是32位整数
var y = +a;  // y 是64位浮点数

而函数的写法如下:

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

上述的函数参数及返回值都需要声明类型,这里都是 32 位整数。

而且 asm.js 也不提供垃圾回收机制,内存操作都是由开发者自己控制,通过 TypedArray 直接读写内存:

var buffer = new ArrayBuffer(32768); // 申请 32 MB 内存
var HEAP8 = new Int8Array(buffer); // 每次读 1 个字节的视图 HEAP8
function compiledCode(ptr) {HEAP[ptr] = 12;return HEAP[ptr + 4];
}

从上可见,asm.js 是一个严格的 JavaScript 子集要求变量的类型在运行时确定且不可改变,且去除了 JavaScript 拥有的垃圾回收机制,需要开发者手动管理内存。这样 JS 引擎就可以基于 asm.js 的代码进行大量的 JIT 优化,据统计 asm.js 在浏览器里面的运行速度,大约是原生代码(机器码)的 50% 左右。

推陈出新

但是不管 asm.js 再怎么静态化,干掉一些需要耗时的上层抽象(垃圾收集等),也还是属于 JavaScript 的范畴,代码执行也需要 Parser-Compiler 这两个过程,而这两个过程也是代码执行中最耗时的。

为了极致的性能,Web 的前沿开发者们抛弃 JavaScript,创造了一门可以直接和 Machine Code 打交道的汇编语言 WebAssembly,直接干掉 Parser-Compiler,同时 WebAssembly 是一门强类型的静态语言,能够进行最大限度的 JIT 优化,使得 WebAssembly 的速度能够无限逼近 C/C++ 等原生代码。

相当于下面的过程:

无需 Parser-Compiler,直接就可以执行,同时干掉了垃圾回收机制,而且 WASM 的静态强类型语言的特性可以进行最大程度的 JIT 优化。

WebAssembly 初探

我们可以通过一张图来直观了解 WebAssembly 在 Web 中的位置:

WebAssembly(也称为 WASM),是一种可在 Web 中运行的全新语言格式,同时兼具体积小、性能高、可移植性强等特点,在底层上类似 Web 中的 JavaScript,同时也是 W3C 承认的 Web 中的第 4 门语言。

为什么说在底层上类似 JavaScript,主要有以下几个理由:

  • 和 JavaScript 在同一个层次执行:JS Engine,如 Chrome 的 V8
  • 和 JavaScript 一样可以操作各种 Web API

同时 WASM 也可以运行在 Node.js 或其他 WASM Runtime 中。

WebAssembly 文本格式

实际上 WASM 是一堆可以直接执行二进制格式,但是为了易于在文本编辑器或开发者工具里面展示,WASM 也设计了一种 “中间态” 的文本格式,以 .``wat.wast 为扩展命名,然后通过 wabt 等工具,将文本格式下的 WASM 转为二进制格式的可执行代码,以 .wasm 为扩展的格式。

来看一段 WASM 文本格式下的模块代码:

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

上述代码逻辑如下:

  • 首先定义了一个 WASM 模块,然后从一个 imports JS 模块导入了一个函数 imported_func ,将其命名为 $i ,接收参数 i32
  • 然后导出一个名为 exported_func 的函数,可以从 Web App,如 JS 中导入这个函数使用
  • 接着为参数 i32 传入 42,然后调用函数 $i

我们通过 wabt 将上述文本格式转为二进制代码:

  • 将上述代码复制到一个新建的,名为 simple.wat 的文件中保存
  • 使用 wabt 进行编译转换

当你安装好 wabt 之后,运行如下命令进行编译:

wat2wasm simple.wat -o simple.wasm

虽然转换成了二进制,但是无法在文本编辑器中查看其内容,为了查看二进制的内容,我们可以在编译时加上 -v 选项,让内容在命令行输出:

wat2wasm simple.wat -v

输出结果如下:

可以看到,WebAssembly 其实是二进制格式的代码,即使其提供了稍为易读的文本格式,也很难真正用于实际的编码,更别提开发效率了。

将 WebAssembly 作为编程语言的一种尝试

因为上述的二进制和文本格式都不适合编码,所以不适合将 WASM 作为一门可正常开发的语言。

为了突破这个限制,AssemblyScript 走到台前,AssemblyScript 是 TypeScript 的一种变体,为 JavaScript 添加了 WebAssembly 类型 可以使用 Binaryen 将其编译成 WebAssembly。

WebAssembly 类型大致如下:

  • i32、u32、i64、v128 等
  • 小整数类型:i8、u8 等
  • 变量整数类型:isize、usize 等

Binaryen 会前置将 AssemblyScript 静态编译成强类型的 WebAssembly 二进制,然后才会交给 JS 引擎去执行,所以说虽然 AssemblyScript 带来了一层抽象,但是实际用于生产的代码依然是 WebAssembly,保有 WebAssembly 的性能优势。AssemblyScript 被设计的和 TypeScript 非常相似,提供了一组内建的函数可以直接操作 WebAssembly 以及编译器的特性.

内建函数:

  • 静态类型检查:

- function isInteger<T>(value?: T): ``bool

  • 实用函数:

- function sizeof<T>(): usize

  • 操作 WebAssembly:

- 数学操作

- function clz<T>(value: T): T

- 内存操作

- function load<T>(ptr: usize, immOffset?: usize): T

- 控制流

- function select<T>(ifTrue: T, ifFalse: T, condition: ``bool``): T

- SIMD

- Atomics

- Inline instructions

然后基于这套内建的函数向上构建一套标准库。

标准库:

  • Globals
  • Array
  • ArrayBuffer
  • DataView
  • Date
  • Error
  • Map
  • Math
  • Number
  • Set
  • String
  • Symbol
  • TypedArray

如一个典型的 Array 的使用如下:

var arr = new Array<string>(10)// arr[0]; // 会出错 												

为什么说 WASM 是 Web 的未来?相关推荐

  1. 解析:Web前端未来的前景如何呢?

    随着互联网的发展,越来越多的企业更加注重用户体验,一个产品想要在日益更新的市场中吸引用户的关注,首先需要做到在用户层面上的良好体验,那么想要做到这些就需要Web前端工程师的技术来实现,因此行业内对于优 ...

  2. 与WebXR共同创建者Diego Marcos一起探讨沉浸式Web的未来(上)

    点击上方"LiveVideoStack"关注我们 翻译 | Alex 技术审校 | 刘连响 本文来自UploadVR,作者为David Heaney WebXR 影音探索 #005 ...

  3. web前端培训班多少钱-web行业未来发展如何

    web前端培训班多少钱-web行业未来发展如何 相信现在众多想要学习Java的学员中,多数是以顺利就业为目的的,那么,我们就不得不考虑一个问题:Java现在的就业前景怎么样?这个问题,我们要从以下几个 ...

  4. 苹果拒绝支持PWA,有损Web的未来

    作者:Greg Blass 翻译:疯狂的技术宅 说明:本文是美国的资深开发者 Greg Blass 针对对苹果公司的激烈吐槽 英文原文:https://medium.com/philly-dev-sh ...

  5. 与WebXR共同创建者Diego Marcos一起探讨沉浸式Web的未来(下)

    点击上方"LiveVideoStack"关注我们 翻译 | Alex 技术审校 | 刘连响 本文来自UploadVR,作者为David Heaney WebXR 影音探索 #006 ...

  6. 预测一下web前端未来的6个趋势

    web前端教程 用大白话,来讲编程 2018年上半年结束了,前端技术的发展也将进入到一个相对稳定的阶段, 就前端主流技术框架的发展而言,过去的几年里发展极快,在填补原有技术框架空白和不足的同时也渐渐趋 ...

  7. Web 创始人 Berners-Lee 创办基金会推进 Web 的未来

    World Wide Web 的创始人 Tim Berners-Lee 即将创办一个基金会(World Wide Web Foundation)旨在扩展 Web 的现有功能并将 Internet 送到 ...

  8. Web开发未来会完全替代客户端开发吗?

    大家好,我是 ConardLi. 首先问大家一个问题,现在有一项业务需求,这个需求使用客户端应用实现还是网页来实现你会考虑哪些因素呢?可以在评论区告诉我. 曾几何时,想到网页可能我们第一时间想到的就是 ...

  9. 基于FFmpeg和Wasm的Web端视频截帧方案

    作者 | 小萱 导读 基于实际业务需求,介绍了自定义Wasm截帧方案的实现原理和实现方案.解决传统的基于canvas的截帧方案所存在的问题,更高效灵活的实现截帧能力. 全文10103字,预计阅读时间2 ...

最新文章

  1. 溢出漏洞利用小结(基础)
  2. 独家 | 如何利用大规模无监督数据建立高水平特征?
  3. 不忘初心,砥砺前行——写在数据院成立四周年之际
  4. nginx 只允许/不允许 其他域名直接访问
  5. Socket通信(一)
  6. 计算机视觉开源库OpenCV形态学morphologyEx函数之开运算和闭运算
  7. Java版本的Bot Framework SDK
  8. 压力与动力是否成正比?
  9. 整样运用计算机考试,2017年9月计算机二级考试《MS Office高级应用》上机操作题(2)...
  10. HTML列表内容自动排序,JS实现HTML表格排序功能
  11. excel显著性检验_怎样征服老板?教你用excel找到数据之间隐藏信息
  12. 语言编奇数和合偶数和_Go语言基础(三)
  13. 六石管理学:做产品,要确定自己是太子还是陪太子
  14. 百度笔试题——页面调度算法
  15. VS在新建或者导入项目时出现“不支持此接口(Exception from HRESULT:0x80004002 (E_NONINTERFACE))”的解决办法
  16. 使照片带有妙的电影色彩55款工具套件的lr微妙的电影调色预设
  17. linux如何查看mac地址_查看mac地址 linux_linux查看mac地址
  18. python 批量替换当前.txt文本内容
  19. PG内核分析 Question and Answer
  20. Accumulation Degree题解

热门文章

  1. 树莓派输出高电平C语言,树莓派控制高电平蜂鸣器(c语言+新手向)
  2. WMI Provider Host占用CPU过高
  3. 大数据与云计算学习(2)
  4. 以太坊P2P中Kad算法解析
  5. 华为虚拟服务器 vrm,安装虚拟化管理服务器-VRM
  6. 成绩查询源码mysql_基于PHP+MYSQL的成绩查询系统(含源码)
  7. 电销企业存在的三大难题
  8. SRV记录生成的完整教程
  9. Python math.sin() 方法
  10. HHVM安装(centos6.3下)