且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Chrome 96 支持 WebAssembly 引用类型了!

更新时间:2022-08-14 19:37:27

11月16日正式发布的Chrome 96,带来了哪些新特性呢?

TL;TR

  • Chrome 96最大的亮点是什么?这一次的主角依然是WebAssembly,它有了引用类型!
  • Chrome 96是哪天发布的?2021-11-16
  • Chrome 96更新了多少个特性?一共20个特性,其中12个新特性,4个试用特性,3个开发特性,1个废弃特性,具体有哪些特性可以查看Chrome Platform Status
  • Chrome 96将使用哪个版本的V8引擎?v9.6
  • 我感兴趣的正式特性有哪些?
    • WebAssembly Reference Types
    • HTTPS DNS records
  • 我感兴趣的试用(origin trial)特性有哪些?
    • Priority Hints
    • WebAssembly Dynamic Tiering

详细解读

WebAssembly Reference Types

Chrome 96正式发布了WebAssembly Reference Types,Reference Types即引用类型,用externref关键词表示。

之前,WebAssembly仅支持32位及64位的整数和浮点数,这样使得处理复杂数据比如String和Object时非常麻烦。

以字符串为例,如果我们需要从JavaScript传入一个字符串给WebAssembly函数使用,则需要这样处理:

  • 将字符串转换为整数(使用TextEncoder即可)
  • 将整数写入WebAssembly的内存空间(WebAssembly的内存空间是一个线性的数组空间)
  • 将整数数组的地址传给WebAssembly函数

虽然这些步骤由编译工具比如wasm-bindgen来处理,我们不需要操心,但是这样做会生成大量胶水代码,损耗了编译和执行性能。

支持Reference Types之后,WebAssembly也可以愉快地处理整数及浮点数之外的数据类型了。

WebAssembly/reference-types提案已经被纳入WebAssembly标准,Firefox和Safari之前已经支持了。WebAssembly Reference Types使得其他WebAssembly提案成为可能,例如GC(Garbage collection)、Interface Types以及type Imports等。

WebAssembly/reference-types提案的负责人是Andreas Rossberg,他是Google前员工,参与了WebAssembly最初的设计,现在是WebAssembly核心规范的编辑。除了Reference Types,Andreas Rossberg还负责了WebAssembly的很多其他非常重要的提案,比如GC(Garbage collection)、Type Imports、Tail call等。

我在Chrome 91(《Chrome 91支持WebAssembly SIMD,加速Web在AI等领域的应用》)以及Chrome 95《Chrome 95终于支持WebAssembly异常处理了》)博客中分别介绍过WebAssembly SIMD与WebAssembly Exception Handling,可见,WebAssembly的能力正在变得越来越强大:

「时间」 「Chrome版本」 「特性」
2021-05-25 Chrome 91 WebAssembly SIMD
2021-10-19 Chrome 95 WebAssembly Exception Handling
2021-11-16 Chrome 96 WebAssembly Reference Types

Chrome今年所支持的WebAssembly特性,都是非常关键的,这将进一步促进WebAssembly的应用。

近期,Photoshop近期发布了其Web应用,也是通过将C++编译为WebAssembly来实现的,其中WebAssembly Exception Handling与WebAssembly SIMD发挥了重要的作用。

Chrome 96 支持 WebAssembly 引用类型了!图片来源:Photoshop's journey to the web

对WebAssembly感兴趣的同学,欢迎阅读我的博客《十年磨一剑,WebAssembly是如何诞生的?》,了解WebAssembly的发展历史。

HTTPS DNS records

Chrome 96正式支持了HTTPS DNS records,对于部署了HTTPS DNS records的网站,Chrome将始终使用HTTPS进行连接。

HTTPS DNS records是DNS的新特性,支持在DNS记录中返回除了网站的IP地址之外的一些额外的信息:比如是否支持HTTPS,是否支持HTTP/2以及HTTP/3。

例如,下面的DNS记录表示example.com支持HTTPS,并且支持HTTP/2和HTTP/3:

example.com 3600 IN HTTPS 1 . alpn=”h3,h2”

这样的话,浏览器第一次访问example.com时,可以直接使用HTTPS进行连接。

否则,浏览器不确定example.com是否支持HTTPS,只能先使用HTTP进行连接,若服务端要求重定向到HTTPS,再使用HTTPS进行连接。这样既耗费了1次多余的连接,同时也不安全。

HTTPS DNS records对应的IETF提案为Service binding and parameter specification via the DNS (DNS SVCB and HTTPS RRs),目前尚未成为IETF正式的RFC,不过已经基本稳定了。

其实,从Chrome 91开始,Chrome默认使用HTTPS进行连接,这样对于支持HTTPS的站点,第一次请求已经不是HTTP了,关于这个特性的介绍详见我的Chrome 90博客。该特性原计划Chrome 90发布,后来因为BUG推迟到了Chrome 91。

默认使用HTTPS协议,也是个不错的方法,正经网站谁还用HTTP啊!不过有了HTTPS DNS records更好,浏览器不用再去试错了。

Chrome的核心原则为4S,其中之一为Security(另外3个S分别为Speed、Stability、Simplicity),因此Chrome对于推动HTTPS这件事一向非常执著。

Firefox 83在去年支持了HTTS-Only Mode,"禁止"用户访非HTTPS站点:

Chrome 96 支持 WebAssembly 引用类型了!图片来源:Firefox 83 introduces HTTPS-Only Mode

Chrome 94已经支持用户配置HTTPS-First Mode,未来可能会默认开启。虽然名字不一样,实际效果与Firefox的HTTS-Only Mode差不多。

Priority Hints

Chrome 96开始试用Priority Hints,用于指定页面资源的加载优先级,即importance属性,帮助浏览器根据优先级优化加载顺序,从而优化页面加载体验。

浏览器下载页面资源的顺序由众多因素所决定,比如资源的类型、位置及顺序、是否在可视窗口、是否指定defer、async、preload等。浏览器根据规则确定资源的优先级,从而确定下载顺序。

一般来讲,浏览器可以很好地决定资源下载顺序,但是由于缺乏对具体应用及具体页面的深入理解,浏览器下载资源的顺序很难是最优的。这时,如果我们就可以利用规则来调整资源的优先级,从而影响下载顺序,比如为页面统计/监控脚本指定async。不过这种方法有点隔山打牛的感觉,既复杂又不一定能达到效果。

Priority Hints则非常简单直接,通过important属性指定资源的优先级,其取值为high、low、auto,其中auto为默认值,使用方式如下:

<!-- 通过important属性指定图片的优先级 -->
<img src="/images/test.png" importance="high" />
<!-- 使用fetch的时指定优先级 -->
<script>
  fetch("https://example.com/", { importance: "low" }).then((data) => {});
</script>

不过,importance属性作为浏览器确定资源加载顺序的重要参考,但是并不具备决定性左右。

如下图所示,通过使用Priority Hints提高背景图片的下载优先级,Google Flight将Largest Contentful Paint(简称LCP,即最大内容绘制)从2.6s降低到了1.9s:

Chrome 96 支持 WebAssembly 引用类型了!图片来源:Optimizing resource loading with Priority Hints

从视频可以很明显得看出来,背景图片的加载明显提前了,用户所感知的体验提升了很多:

Chrome 96 支持 WebAssembly 引用类型了!

视频来源:Optimizing resource loading with Priority Hints

Priority Hints为WICG提案,由Google的开发者负责,目前并未得到其他浏览器的支持。

WebAssembly Dynamic Tiering

Chrome 96开始试用WebAssembly Dynamic Tiering,目的是优化WebAssembly的编译过程,改变了之前贪婪的编译方式,以降低对资源的浪费。

这个特性纯粹是V8引擎层面的优化,与应用层开发者没啥关系,不过还挺有意思的,值得了解一下。

V8引擎中有两个编译器用来编译WebAssembly,分别是Liftoff和TurboFan,前者是基础编译器,后者是优化编译器。

Liftoff是one-pass compiler,它只会读取一遍WebAssembly代码,然后直接生成机器代码,这样提高了编译速度,节省了启动时间。不过Liftoff编译的机器代码没有经过太多优化,因此执行性能相对差一些。

Chrome 96 支持 WebAssembly 引用类型了!图片来源:Liftoff: a new baseline compiler for WebAssembly in V8

TurboFan是multi-pass compiler,同时负责WebAssembly和JavaScript的优化编译,它会应用各种方法优化所生成的机器代码,例如优化寄存器的分配。因此TurboFan所生成的机器代码更加高效,不过编译时间更长。

Chrome 96 支持 WebAssembly 引用类型了!图片来源:Launching Ignition and TurboFan

TurboFan的编译过程远比Liftoff复杂(天下没有免费的午餐),如下图所示:Chrome 96 支持 WebAssembly 引用类型了!图片来源:Liftoff: a new baseline compiler for WebAssembly in V8

V8引擎之前编译WebAssembly的策略是这样的:

  • 先使用Liftoff编译WebAssembly代码,编译完成之后就可以执行了,同时立即使用TurboFan(后台线程)将所有WebAssembly的函数重新编译一遍。
  • 每当TurboFan编译完一个WebAssembly函数,则替换掉Liftoff的编译结果,这样当调用该函数时,执行的是经过TurboFan优化编译的机器代码。

这样的编译方式还是挺巧妙的,既提高了启动速度,也保障了执行速度。不过,使用TurboFan将所有WebAssembly函数重新编译一遍的做法,着实有些浪费CPU和内存,比较费电,不符合碳中和的时代背景:

  • 有的WebAssembly函数(如果不是大部分的话)根本不会被调用,为爱编译?
  • TurboFan不使用主线程,不过还是会浪费worker线程的CPU以及内存。
  • TurboFan编译所有函数的话,则有可能会耽误对重要函数的编译,反而降低了性能。

于是,V8计划改变之前贪婪的编译方式,引入Dynamic tiering技术,TurboFan只编译那些执行了多次的WebAssembly函数。

Dynamic tiering听着很厉害的样子,其实与V8引擎编译JavaScript所使用的策略是相同的。对V8引擎如何编译JavaScript感兴趣的话,不妨阅读我2年前的博客《V8引擎是如何工作的?》

既然编译JavaScript时早就这么干了,那为啥V8不早点使用Dynamic tiering来优化WebAssembly编译呢?核心原因目测是WebAssembly是静态类型的,因此Liftoff编译的机器代码已经足够快了,没有JS那么命苦,并不急着需要TurboFan的优化编译。根据Liftoff: a new baseline compiler for WebAssembly in V8的测试结果,Liftoff编译速度比TurboFan快了5~10倍,执行速度比TurboFan慢了18%~100%,使用之前的贪婪编译策略问题也不大。

总结

这篇博客介绍了4个Chrome新特性,拆解下来都会涉及比较基础的知识点:DNS、HTTPS、HTTP、页面加载过程、变量类型、编译技术。所以,看起来我是在追逐最新的技术,其实我是在重温那些最基础的知识点。

所谓"温故而知新",反过来也很有道理,"知新而温故"。这也是我写博客最主要的目的,把写作当成一种学习方法,通过输出倒逼输入。

另外,我从Chrome 94的博客开始介绍试用(origin trial)特性,这样既可以第一时间了解Chrome的最新特性,又可以给我更多的时间熟悉这些特性,当它们正式发布的时候,我还是会把它们写到新版本的博客里面,那时应该会有一些新的内容可以写。

才疏学浅,我所写的内容难免有错误之处,欢迎批评指正,个人微信:「KiwenLau」

参考资料

  • Chrome 96 Beta: Conditional Focus, Priority Hints, and More
  • V8 release v9.6
  • 「Strings in WebAssembly (Wasm)」
  • Making WebAssembly better for Rust & for all languages
  • wast-binden: Support for Reference Types
  • WebAssembly Reference Types in Wasmtime
  • WebAssembly Reference Types Implemented in wasmtime, Lets Wasm Modules Handle Complex Types
  • 「Speeding up HTTPS and HTTP/3 negotiation with... DNS」
  • A safer default for navigation: HTTPS
  • Increasing HTTPS adoption
  • Firefox 83 introduces HTTPS-Only Mode
  • 「Optimizing resource loading with Priority Hints」
  • Largest Contentful Paint (LCP)
  • WebAssembly Dynamic Tiering ready to try in Chrome 96
  • WebAssembly compilation pipeline
  • 「Liftoff: a new baseline compiler for WebAssembly in V8」
  • 「Photoshop's journey to the web」