WebAssembly
首发于WebAssembly
我的新书《深入浅出WebAssembly》出版啦(。・ω・。)ノ

我的新书《深入浅出WebAssembly》出版啦(。・ω・。)ノ

签名版书籍发货需要3-5天,网上商城在正式开始售卖后基本可以当天发货。

这里是网上各大商城的预售链接:

《深入浅出WebAssembly》(于航)【摘要 书评 试读】- 京东图书

《深入浅出WebAssembly》电子工业出版社 - 天猫

《深入浅出WebAssembly》(于航)【简介_书评_在线阅读】 - 当当图书

《深入浅出WebAssembly》 于航【摘要 书评 试读】- 亚马逊图书

《深入浅出WebAssembly》豆瓣图书


或者大家如果需要签名版,或者需要加入本书的微信技术交流群,都可以直接知乎私信我 ;)。


勘误页面:

《深入浅出 WebAssembly》内容勘误


好吧,首先承认,这本书的出版确实延期了。作为国内第一本介绍 WebAssembly 技术的相关书籍,确实还是花了很长的时间来组织内容。整个初稿从写作到最后交稿花了足足 8 个月的时间,最终成书的内容有 530 多页,已经涵盖了 Wasm 技术相关的大部分内容。

但事实上由于 Wasm 现阶段只实现了 MVP 标准中的绝大部分特性,而对于 Post-MVP 标准中的内容,由于标准尚未完全确定,因此本书只讨论了其中的一部分特性,并对其他特性进行了简单的介绍(稍有遗憾,总感觉不够完整)。而如果有机会能够在未来的 1-2 年内重写本书的第二版,则其中可能会再增加 200 页关于新标准(十几种新特性)的内容(迈向 800 页大关 (´・ω・`)),让整个 WebAssembly 的技术体系更加充实和完整!

PS:之前很多朋友问我能否赠书,这里真的很抱歉。因为我虽然作为作者但仍然也是要向出版社买书的。出版社在出版时赠送的几本样书这里只能够优先送给对本书出版做出贡献的序言作者推荐语作者以及帮忙修改校订本书内容的朋友们。因此也就没有多余的赠书能再赠送给各位朋友了,这里真的十分抱歉。但大家可以通过上述列出的第二种方式进行购买,这里由笔者直接向出版社购买本书会有一定的折扣(抱拳。


接下来我会放出本书的完整目录,供大家参考:

# 第1章 漫谈WebAssembly发展史.... 1
## 1.1 JavaScript的发展和弊端.... 1
1.1.1 快速发展与基准测试.... 1
1.1.2 Web新时代与不断挑战.... 8
1.1.3 无法跨越的“阻碍”.... 11
1.1.4 Chrome V8引擎链路.... 17
## 1.2 曾经尝试——ASM.js与PNaCl. 28
1.2.1 失落的ASM.js. 28
1.2.2 古老的NaCl与PNaCl. 42
## 1.3 新的可能——WebAssembly.. 57
1.3.1 改变与颠覆.... 57
1.3.2 一路向前,WCG与WWG.. 85

# 第2章 WebAssembly核心原理(基于MVP标准).... 90
## 2.1 应用与标准Web接口.... 90
2.1.1 编译与初始化.... 90
2.1.2 验证模块.... 106
2.1.3 遇到错误.... 106
2.1.4 内存分配.... 108
2.1.5 表.... 112
## 2.2 深入设计模型——堆栈机.... 118
2.2.1 堆栈式虚拟机.... 119
2.2.2 逆波兰表达式.... 125
2.2.3 Shunting-yard算法.... 126
2.2.4 标签与跳转.... 130
2.2.5 条件语句.... 135
2.2.6 子程序调用.... 137
2.2.7 变量.... 138
2.2.8 栈帧.... 139
2.2.9 堆.... 140
## 2.3 类型检查.... 141
2.3.1 数据指令类型.... 142
2.3.2 基本流程控制.... 144
2.3.3 基于表达式的控制流.... 149
2.3.4 类型堆栈的一致性.... 151
2.3.5 不可达代码.... 155
## 2.4 二进制编码.... 156
2.4.1 字节序——大端模式与小端模式.... 157
2.4.2 基于LEB-128的整数编码.... 161
2.4.3 基于IEEE-754—2008的浮点数编码.... 163
2.4.4 基于UTF-8的字符串编码.... 167
2.4.5 模块数据类型.... 168
2.4.6 虚拟指令与编码.... 169
2.4.7 类型构造符.... 174
## 2.5 模块.... 175
2.5.1 段.... 175
2.5.2 索引空间.... 185
2.5.3 二进制原型结构.... 186
## 2.6 内存结构.... 196
2.6.1 操作运算符.... 197
2.6.2 寻址.... 197
2.6.3 对齐.... 198
2.6.4 溢出与调整.... 203

# 第3章 动态链接与SIMD(基于MVP标准).... 204
## 3.1 动态链接(Dynamic Linking).... 204
3.1.1 ELF.. 206
3.1.2 符号重定向(Symbol Relocation).... 212
3.1.3 GOT(Global Offset Table,全局偏移表).... 225
3.1.4 PLT(Procedure Lookup Table,过程查询表).... 229
3.1.5 基于表的Wasm模块动态链接.... 233
## 3.2 单指令多数据流(SIMD).... 237
3.2.1 SIMD应用.... 239
3.2.2 并行与并发.... 243
3.2.3 费林分类法.... 244
3.2.4 SIMD.js & TC39.. 246
3.2.5 WebAssembly上的SIMD扩展.... 248

# 第4章 深入LLVM与WAT.. 250
## 4.1 LLVM——底层虚拟机.... 250
4.1.1 传统的编译器架构.... 251
4.1.2 LLVM中间表示层.... 252
4.1.3 基于LLVM的编译器架构.... 254
4.1.4 LLVM优化策略.... 256
4.1.5 LLVM命令行工具.... 261
4.1.6 WebAssembly与LLVM... 268
## 4.2 基于LLVM定义新的编程语言.... 272
4.2.1 图灵完备与DSL.. 276
4.2.2 简易词法分析器.... 280
4.2.3 RDP与OPP算法.... 287
4.2.4 AST(抽象语法树).... 295
4.2.5 简易语法分析器.... 296
4.2.6 生成LLVM-IR代码.... 303
4.2.7 链接优化器.... 307
4.2.8 编译到目标代码.... 308
4.2.9 整合I/O交互层.... 312
## 4.3 WAT.. 315
4.3.1 S-表达式.... 317
4.3.2 WAT/Wasm与Binary-AST.. 318
4.3.3 其他与设计原则.... 320

# 第5章 Emscripten基础应用.... 322
## 5.1 利器——Emscripten工具链.... 322
5.1.1 Emscripten发展历史.... 322
5.1.2 Emscripten组成结构.... 324
5.1.3 Emscripten下载、安装与配置.... 326
5.1.4 运行测试套件.... 330
5.1.5 编译到ASM.js. 331
## 5.2 连接C/C++与WebAssembly.. 333
5.2.1 构建类型.... 334
5.2.2 Emscripten运行时环境.... 342
5.2.3 在JavaScript代码中调用C/C++函数.... 351
5.2.4 在C/C++代码中调用JavaScript函数.... 363

# 第6章 基于Emscripten的语言关系绑定.... 382
## 6.1 基于Embind实现关系绑定.... 384
6.1.1 简单类.... 389
6.1.2 数组与对象类型.... 391
6.1.3 高级类元素.... 393
6.1.4 重载函数.... 407
6.1.5 枚举类型.... 408
6.1.6 基本类型.... 409
6.1.7 容器类型.... 411
6.1.8 转译JavaScript代码.... 413
6.1.9 内存视图.... 416
## 6.2 基于WebIDL实现关系绑定.... 417
6.2.1 指针、引用和值类型.... 420
6.2.2 类成员变量.... 422
6.2.3 常量“const”关键字.... 423
6.2.4 命名空间..... 424
6.2.5 运算符重载.... 425
6.2.6 枚举类型.... 426
6.2.7 接口类.... 429
6.2.8 原始指针、空指针与void指针.... 431
6.2.9 默认类型转换.... 434

# 第7章 探索Emscripten高级特性.... 437
## 7.1 加入优化流程.... 437
7.1.1 使用编译器代码优化策略.... 442
7.1.2 使用GCC压缩代码.... 444
7.1.3 使用IndexedDB缓存模块对象.... 446
7.1.4 其他优化参数.... 453
## 7.2 使用标准库与文件系统.... 454
7.2.1 使用基于musl和libc++的标准库.... 455
7.2.2 虚拟文件系统结构.... 458
7.2.3 打包初始化文件.... 460
7.2.4 基本文件系统操作.... 461
7.2.5 懒加载.... 470
7.2.6 Fetch API. 474
## 7.3 处理浏览器事件.... 479
7.3.1 事件注册函数.... 480
7.3.2 事件回调函数.... 481
7.3.3 通用类型与返回值类型.... 482
7.3.4 常用事件.... 484
## 7.4 基于EGL、OpenGL、SDL和OpenAL的多媒体处理.... 487
7.4.1 使用EGL与OpenGL处理图形.... 488
7.4.2 使用SDL处理图形.... 494
7.4.3 使用OpenAL处理音频.... 497
## 7.5 调试WebAssembly应用.... 500
7.5.1 编译器的调试信息.... 500
7.5.2 使用调试模式.... 502
7.5.3 手动跟踪.... 503
7.5.4 其他常用编译器调试选项.... 505

# 第8章 WebAssembly综合实践、发展与未来.... 506
## 8.1 DIP综合实践应用.... 506
8.1.1 应用描述.... 506
8.1.2 滤镜与卷积.... 507
8.1.3 基本组件类型与架构.... 511
8.1.4 编写基本页面骨架(HTML与CSS).... 512
8.1.5 编写核心卷积函数(C++).... 513
8.1.6 编写主渲染循环与“胶水”代码(JavaScript).... 515
8.1.7 使用Emscripten编译并运行应用.... 520
8.1.8 性能对比.... 521
## 8.2 WebAssembly常用工具集.... 522
8.2.1 Cheerp.. 522
8.2.2 Webpack 4.. 524
8.2.3 Go和Rust的WebAssembly实践.... 526
8.2.4 Binaryen.. 529
8.2.5 WasmFiddle. 530
8.2.6 Wabt. 531
8.2.7 AssemblyScript. 531
## 8.3 WebAssembly未来草案.... 531
8.3.1 GC(垃圾回收).... 532
8.3.2 Multi-Thread(多线程)与原子操作.... 532
8.3.3 异常处理.... 532
8.3.4 多返回值扩展.... 532
8.3.5 ES模块.... 532
8.3.6 尾递归.... 533
8.3.7 BigInts的双向支持.... 533
8.3.8 自定义注释语法.... 533

下面是本书的部分前言,主要介绍了本书的写作背景,适合人群以及致谢(这个必须有):

为什么要写这本书

自从JavaScript(后面简称JS)脚本语言于1995年诞生以来,人们便一直在使用该语言以及HTML 与 CSS 来编写和开发以浏览器为主的 Web 应用。近年来,随着JS的不断流行,以及Node.js 的出现,JS 也开始逐渐向除 Web 前端之外的其他领域发力,比如开发后端应用、机器学习应用乃至硬件编程等领域。但就 JS 本身而言,所不能无视的是它是一种弱类型语言,因此,相比于 C/C++ 等强类型语言,尽管 Chrome V8、SpiderMonkey 等 JS 引擎已经通过诸如 JIT 等多种技术手段来优化 JS 脚本代码的整体执行效率,但引擎每一次版本优化的迭代速度(所花费的时间)却远远跟不上当今各类 Web 应用的复杂程度变化。因此,发明一种能够从根本上解决该问题的技术便显得迫在眉睫。

曾昙花一现的 ASM.js、NaCl 与 PNaCl 等技术都尝试以其各自的方式来优化 Web 应用的执行效率,但由于其所存在的诸如“浏览器兼容性不佳”以及“性能优化不彻底”等问题,导致它们最终并没有被广泛推广。而在2015年出现的 WebAssembly(简称 Wasm)技术,便是在吸取了前者经验教训的基础上而被设计和发明出来的。现在,我们可以看到该项技术所具有的潜力——W3C 成立了专门的 WWG 工作组来负责 Wasm 技术的标准迭代与实现,四大主流浏览器(Google Chrome、FireFox、Edge和Safari)已经全部实现 WebAssembly 技术在其 MVP 标准中制定的所有特性,C/C++、Go 和 Rust 等高级语言已经逐渐开始支持编译到 Wasm 格式。这一系列的发展和变化都说明了人们对该项技术所寄予的厚望。

如今世间百态,万物的发展速度越来越快,而前端技术领域也同样如此,正在转向技术融合的道路——从2000年专门指代 PC 网页技术的 Web 前端,到2010年左右包含有 H5 技术的前端,再到融合了移动端甚至部分后端技术的“大前端”。“前端”一词所指代的技术实体正变得越来越模糊,已经不单单是指我们所熟知的 JS、HTML 与 CSS 了,正如大学里生物学专业与化学专业两者融合后所形成的“生物化学专业”一样。技术本身并无好坏之分,只有能否适用于某些业务场景。而技术的融合则正好能够发挥各项技术本身所具备的优势,达到“1+1>2”的效果。WebAssembly 技术便正是如此。

在写作本书的过程中,笔者曾与 WWG 的核心成员 Alon、Ben 和 JF 等专家进行了多次交流,以力求保证书中各个技术细节的正确性。但 Wasm 技术发展非常之快,比如 Emscripten 工具链每天都会有众多的 “commit” 被提交到主分支中,新版本的发布也是以“周”甚至“天”为单位进行的。因此,书中所述内容并不保证会在今后的半年甚至一年时间里都具有时效性。而对于相关内容的时效性变化,笔者也会在对应于本书的 Github 仓库(详见“勘误和支持”部分)中及时进行标注。作为国内第一本介绍 WebAssembly 的技术书籍,希望本书的内容能够为国内互联网基础技术的发展做出微小的贡献。虽然现阶段我们还无法完全地自主创新,或者参与到各项国际技术标准的制定过程中,但唯有紧跟其脚步,才能够伺机超越。

本书特色

作为市面上第一本深入介绍 WebAssembly 技术的相关书籍,笔者尝试由浅入深地来介绍与Wasm 技术相关的各种底层理论知识,以及相关编译器工具链的内部实现结构与使用方法。WebAssembly 技术从其第一版 MVP 标准诞生至今,时间过去并不久,但抽象的英文官方文档并不适合各类 Web 前端开发工程师直接进行阅读。从另一个方面来看,虽然我们可以在国内如“百度”等中文搜索引擎上找到部分与 Wasm 实践相关的介绍文章,但它们大都不会深入该技术标准的背后,探寻该技术的底层设计本质。因此,本书力求从一些简单的实践入手,深入理论,再到复杂的具有实际业务价值的综合实践,深入浅出地介绍 Wasm 技术发展至今,其背后所涉及的各种底层设计原理与实现、相关工具链以及未来发展方向等多方面内容。

由于 WebAssembly 并不是一种单方面的前端或后端技术,因此在本书中,我们将会随着内容的深入逐渐接触到除Web前端技术之外的诸如编译原理、V8 引擎、LLVM 以及 Linux 动态链接等多方面内容。笔者将会用最简单和直观的方式,由浅入深地介绍这些平日里可能很少接触到的技术与特性。

另外,作为市面上首本与 WebAssembly 相关的纯技术类书籍,笔者只能从自己所接触到的Wasm 相关技术中,按照各个知识点的相关性与重要性来编排内容。相信读者在读完整本书后,一定会对 Wasm 技术背后的实现原理以及相关技术有着进一步的理解。

读者对象
  • Web 前端开发人员。
  • C/C++ 开发人员。
  • 对 WebAssembly 技术感兴趣的人员。
致谢

首先要感谢的是 Emscripten 工具链的作者 Alon,在编写 Emscripten 实践部分时,通过邮件与他沟通了很多技术细节上的内容。Alon 是 Mozilla 的技术研究员,他主要负责维护和开发Emscripten 与 Binaryen 两个重要的 WebAssembly 工具链。Alon 平日工作繁忙,非常感谢他能够抽出时间为我指导技术,以及本书内容组织方面的事情,并为本书写了序言。

还要感谢的是我的好友以及家人。早早地立下写书的誓言,正是因为有了你们每天的监督,我才能督促自己完成每天规定的任务,最终完成本书所有章节的编写。

最后要感谢的是本书的策划编辑张春雨,2017年上海 QCon 全球软件开发大会之后,他通过微信找到了作为讲师的我,并给予我这次写书的机会。但十分抱歉的是,由于我的日程和时间安排不当,导致本书的出版比预定时间晚了近三个月。但张老师并没有放弃我,这里真的要说一声:“感谢您对我的信任”。

除此之外,还要感谢帮忙写序和推荐语的 @Alon Zakai @Devoation(赵洋) @知三乎四(勾股) @王泽 @pockry(徐川) @郭力恒 以及帮忙修订序言译文的 @薛命灯 童鞋,谢谢你们!

关于源码和勘误

本书的源码仓库可以单独使用:

github.com/Becavalier/B

github.com/Becavalier/C

* 由于笔者水平有限,因此书中内容难免会出现不严谨或错误的问题。而对相应问题的勘误则会放在上述仓库的 “Issue” 页中进行说明和更正。也欢迎各位朋友踊跃发现错误或提出观点,以帮助本书内容的进一步优化。


最后就是从理论到实践的一公里,下面是笔者之前写的一个的基于 Wasm 构建的 VDOM 差异(diff)计算引擎,现在已经有了一个大致的原型版本。最近接二连三的好消息都预示着 Wasm 技术能够在 Web 前端开发领域大显身手。基于 Reference Type 和 Host Binding 带来的对 JavaScript 数据元素的高效引用,以及 JavaScript 引擎的持续优化使得在两个 Context 之间的函数相互调用成本大大降低。未来 Wasm 在纯 Web 前端领域的实践将会越来越多(这里预言一波:三年之后30%以上的 Web 应用都会直接或间接使用 Wasm 技术)。

Becavalier/Sharpengithub.com图标

如下图所示为原型版 Sharpen 在本地进行测试时的差异计算与渲染效果。对于下面两段不大的 HTML 片段进行基于 VDOM 的差异计算和渲染过程其整体消耗时间在 2ms-4ms 之间(这里虽然没有写对应 JavaScript 版本的实现以用来进行对照的 Benchmark,但这个耗时实际上应该算是很高的了,并且在 HTML 片段足够大的时候两者的性能差异会凸显出来)。

Original:

<div id="native" data-tid="apple" data-type="div">
  <span style="font-size: 12px; font-weight: bold;">Apple</span>
  <h4>A very cool company!</h4>
</div>

Patch:

<div id="patch" onclick="alert(true);" style="background-color: yellow;" data-sid="google" data-type="div"> 
  <span style="font-size: 20px; color: blue; font-weight: bold;">谷歌</span>
  <p>一家伟大的公司!</p>
  <p style="color: red;">share: $1164.83</p>
</div>

整个计算和渲染过程可以分为如下几个阶段,其中背景为浅灰色的过程占用了一部分不必要的性能损耗,并且当 HTML 片段的“体积”逐渐增大时,这6个过程所占用的处理时间会进一步增大以至于严重影响整个引擎的计算性能。现阶段我们可以采用“特化”的 JSON 解析器以及异步垃圾回收等“边缘策略”来尽可能降低这些不必要过程的性能损耗,但其效果也并不尽如人意。当然,在处理大而复杂的 VDOM 片段时,使用多线程以及 LD 算法也是有一定必要的。所以我们只能期待等后续 Post-MVP 相关特性实现后再来解决这个棘手的问题。

就像 Clark 所说的,Wasm 发展到现在也只是刚刚开始:“So the WebAssembly that we have today is not the end of this story—it’s just the beginning.” 但其未来的发展蓝图确是十分宏大的,包括 WAVM 在内的 WebAssembly 运行时环境(虚拟机)可以将 Wasm 的应用范围延伸到诸如:CDN、区块链(如”以太坊虚拟机 EVM“)、IOT以及常用命令行工具等多个领域。除此之外,诸如 Vuejs、React、Angular 等前端 JavaScript 框架也会因此而发生相应的改变。因此未来几年 Wasm 将会带给 Web 世界的新变革是非常令人值得期待的。


最后的最后,放两张自拍以感谢各位客官老爷对“魔女.曜彤”(王婆卖瓜,自卖自夸)的支持 (´・Д・)」,谢谢!同时赶在节日的尾巴,也祝大家🎃万圣节🎃快乐,trick or treat!

编辑于 2019-03-03

文章被以下专栏收录