前言
本文章是渲染引擎北海 (Kraken) v0.9 的发布日志,如果你对 Kraken 还不了解,不妨先跳转到本文末尾阅读我们之前发布的文章。
继 v0.8 升级到 Flutter 2.0 + Null Safety 之后,在这个版本我们重点对首屏的加载性能、布局的正确性和性能以及前端社区生态做了重点优化,详细的更新日志可见 CHANGELOG。
接下来我会重点介绍在 v0.9 加入的几大新特性。
支持 QuickJS 作为 JavaScript Engine
QuickJS 是一个轻量级的 JavaScript 引擎,与 JavaScriptCore 相比它具有以下几个优点:
- 轻量,它的实现仅仅由几个 C 文件,没有外部依赖,一个 x86 下的简单的 “hello world” 程序只要约 180 KiB。
- 具有极低启动时间的快速解释器,配合将 JS 源码预编译为 bytecode 格式,忽略解析耗时后对应用启动性能有很大提升。
- 几乎完整的 ECMA 标准支持,最新版本原生支持 ES2020,不再需要 babel 编译为 ES5,不仅 JSBundle 体积可以下降,也能提升执行的性能。
- 更好的多平台支持,即使完整编译也不需要耗费太多工夫。
Kraken v0.9 将原先的 Bridge 层的 JavaScript Engine 默认实现迁移为 QuickJS,配合 bytecode 预编译可以将应用启动性能得到提升。而且这些改动对前端开发者是完全无感的。
我们也对 Kraken 新版本和上一个版本进行了 Benchmark 性能测试:
测试设备: MI 6 (Android arm64)
测试方法:使用 0.8.4(JavaScriptCore) 和 0.9.0-rc(QuickJS) 版本各冷启动一次页面,对比加载耗时。
详细日志:
分析日志中与 JavaScript 相关的关键性能指标:
- js_context_init_cost:JS Engine 初始化耗时
- polyfill_init_cost:Kraken JS polyfill 初始化耗时
- js_bundle_eval_cost:JS Bundle 执行耗时
- js_parse_time_cost:JS Bundle 解析耗时
Version | js_context_init_cost | polyfill_init_cost | js_bundle_eval_cost | js_parse_time_cost | |
---|---|---|---|---|---|
0.8.4 | 17.30ms | 20.39ms | 229.53ms | 31.25ms | |
0.9.0-rc | 0.55ms | 2.06ms | 122.61ms | 122.91ms |
QuickJS 支持 bytecode 加载,故 js_parse_time_cost
在使用 bytecode 格式的时候可几乎忽略不计。
得到有关 JS 的总加载耗时:
- JavaScriptCore: 17.3 + 20.39 + 229.53 + 31.25 = 298.47ms
- QuickJS: 0.55 + 2.06 + 122.61 = 125ms
真机录屏验证
以上属于代码级别的 Benchmark 数据,实际用户体感效果如何呢,我们在真机上进行了录屏测试:
指标定义:
- 白屏阶段:从用户点击 App 启动到页面首帧出现的时间
- 渲染阶段:从页面首帧出现到目标页所有内容(含图片)渲染稳定完成的时间
通过逐帧分析,多组取平均值得到以下数据:
受限于视频播放器进度条的精度,测试数据精度为 0.05s。
测试分组 | 白屏阶段 (均值) | 渲染阶段 (均值) |
---|---|---|
0.8.4 | 0.95s | 0.80s |
0.9.0-rc | 0.95s | 0.60s |
0.9.0-rc + bytecode | 0.76s | 0.66s |
可得结论,在上述条件下,Kraken v0.9 + bytecode 模式相比 v0.8 版本在首屏性能上可再提升 18.86%。值得注意的是,真机测试使用的是一台 Android 中端设备,JS Engine 解析耗时的影响在低端设备上影响更大,故有理由相信 QuickJS 带来的优化在低端设备上可以获得更多的收益,具体数据我们也将进一步测试更新。
支持 HTML 文件的解析和渲染
对浏览器来说,SSR 直出渲染的性能要比异步 JS 渲染的 CSR 要好上不少,对于 Kraken 也是如此。这次我们给 Kraken 带来了 HTML 文件解析渲染的支持,直接解析 HTML 并渲染视图,无需等待 JS 的初始化与执行。
使用上与 JSBundle 并无任何不同,只需要将 HTML 文件的 URL 传入 bundleURL 即可:
void main() {
runApp(Kraken(
bundleURL: 'https://domain.com/url/to/html',
));
}
Kraken 会根据 HTTP Content-Type
协商使用 HTML 解析或者是 JavaScript 引擎启动。
性能测试:
测试设备: MI 11 Lite (Android arm64)测试方法:使用 0.9.0-rc 分别用 JSBundle / Bytecode / HTML 格式各冷启动一次页面,对比加载耗时。
测试分组 | Total time cost (平均) |
---|---|
JS Bundle | 865ms |
Bytecode | 662ms |
HTML | 255ms |
支持 HTTP 协议的缓存特性
众所周知,编程的终极问题有两个,其一是给变量命名,另一个就是缓存的使用。
在浏览器中默认支持 HTTP 缓存,包含强缓存、协商缓存,它是由多个 HTTP Headers 组合形成的一种描述缓存的规范。而在客户端生态或者 Flutter 的基础能力中,都是不包含 HTTP 缓存功能的。Kraken v0.9 开始默认支持了 HTTP 缓存功能,无论是 XHR/fetch 或者是通过 img 标签加载的图片,script 标签加载的 JS 文件等,只要是从 Kraken 内部发出的 HTTP(s) 请求,都能够享受到缓存带来的收益,目前支持的特性包括:
无需二次请求的强缓存
- Expires
- Cache-Control (max-age/no-store/no-cache)
需要二次请求的协商缓存 (根据 HTTP 状态码 304 协商)
- Last-Modified / If-Modified-Since
- Etag / If-None-Match
本功能对于电商商品 Feeds 流等页面中包含大量图片的场景,带来的优化收益更明显,由于图片几乎全是强缓存类型的资源,在缓存命中的情况下无需再次请求网络,且缓存是落磁盘的固化式缓存,对于二次冷启应用也能享受到优化。
支持 Vue/React 官方工具链
前端开发者是 Kraken 面向的用户,在开源之后我们也持续收到了许多社区开发者的反馈。
对于现代前端开发来说,框架是必不可少的,除了淘系广泛使用的 Rax,最近我们也对 Vue 和 React 的官方工具链、生态库进行了支持,现在使用 v0.9 开发 Vue/React App 会更加顺畅。
具体可参考官方示例工程:https://github.com/openkraken/samples
支持模块热更新 (Hot Module Replacement)
模块热更新是 Webpack 的常用功能,通过它可以在修改代码后直接替换、添加或者删除节点,而无需重新加载整个页面。Webpack 官方说明文档
支持 querySelector / querySelectorAll*
同时我们也对呼声比较大的 querySelector/querySelectorAll
做了支持,目前已支持的 CSS 选择器包括:
- id ID 选择器
- class 类名选择器
- tag 标签选择器
attr 属性选择器,包含以下几种判断
- =
- ^=
- *=
- $=
*:目前仅支持部分 CSS 选择器,详见上述说明。
关于北海 KRAKEN 更多的内容
社区协作机制
我们期望通过一种良好的社区协作机制,来与社区的众多开发者一起共建 Kraken 底层能力及生态。
Kraken 团队通过协作者的方式来参与 Kraken 功能迭代以及 issue 讨论等工作。同时,通过由一部分协作者组成的技术委员会(TSC)来确定技术方向、发布以及定制标准等工作。
简单地说,只要向 Openkraken Group 提交一定质量和数量的代码即可成为协作者;对项目提交建设性的贡献后,TSC 成员有权提名协作者参与到 TSC 中。
Kraken 团队期望通过一种友好、共同参与的协作机制,让社区的开发者能够更好地参与到对项目的演进中去,让每个人的声音都能被听到,共同促进 Kraken 以及 Web 标准 的发展。
更详细的协作机制可以移步 Github TSC。
联系我们
详细的 CHANGELOG 可以查阅 CHANGELOG。 如若希望获取更多关于 Kraken 的信息,可以访问我们的 Github、官方文档 与 Kraken 项目组取得联系。