万字长文讲透微信小程序的底层架构

面试官的一个问题,让我深思了很久,同样是浏览器引擎为什么微信小程序没有window?接下来我们就一同了解下微信小程序的底层,这样再回答这个问题就不难了~😄

本篇分为几个章节:

1.小程序的双线程架构设计

2.双线程对比单线程的优势在哪里

3.传统h5开发环境有什么弊端

一、双线程

小程序开发框架的口号是简单、高效的方式让开发者可以在微信中开发具有原生 APP 体验的服务。

小程序框架分为两部分:逻辑层(App Service)和 视图层(View)。视图层即WXML 和 WXSSJavaScript 即逻辑层,视图层与逻辑层间的数据传输和事件系统依托于微信app,这既是双线程。

小程序一直以来采用的都是 AppService 和 WebView 的双线程模型,基于 WebView 和原生控件混合渲染的方式,小程序优化扩展了 Web 的基础能力,保证了在移动端上有良好的性能和用户体验。Web 技术至今 30 多年历史,作为一款强大的渲染引擎,它良好兼容性和丰富的特性。 尽管各大厂商在不断优化 Web 性能,但由于其繁重的历史包袱和复杂的渲染流程,使得 Web 在移动端的表现与原生应用仍有一定差距。为了进一步优化小程序性能,提供更为接近原生的用户体验,我们在 WebView 渲染之外新增了一个渲染引擎 Skyline,其使用更精简高效的渲染管线,并带来诸多增强特性,让 Skyline 拥有更接近原生渲染的性能体验。

当小程序基于 WebView 环境下时,WebView 的 JS 逻辑、DOM 树创建、CSS 解析、样式计算、Layout、Paint (Composite) 都发生在同一线程,在 WebView 上执行过多的 JS 逻辑可能阻塞渲染,导致界面卡顿。以此为前提,小程序同时考虑了性能与安全,采用了目前称为「双线程模型」的架构。

在 Skyline 环境下,我们尝试改变这一情况:Skyline 创建了一条渲染线程来负责 Layout, Composite 和 Paint 等渲染任务,并在 AppService 中划出一个独立的上下文,来运行之前 WebView 承担的 JS 逻辑、DOM 树创建等逻辑。这种新的架构相比原有的 WebView 架构,有以下特点:

  • 界面更不容易被逻辑阻塞,进一步减少卡顿

  • 无需为每个页面新建一个 JS 引擎实例(WebView),减少了内存、时间开销

  • 框架可以在页面之间共享更多的资源,进一步减少运行时内存、时间开销

  • 框架的代码之间无需再通过 JSBridge 进行数据交换,减少了大量通信时间开销

而与此同时,这个新的架构能很好地保持和原有架构的兼容性,基于 WebView 环境的小程序代码基本上无需任何改动即可直接在新的架构下运行。WXS 由于被移到 AppService 中,虽然逻辑本身无需改动,但询问页面信息等接口会变为异步,效率也可能有所下降;为此,我们同时推出了新的 Worklet 机制,它比原有的 WXS 更靠近渲染流程,用以高性能地构建各种复杂的动画效果。

新的渲染流程如下图所示:

支持与 WebView 混合使用

小程序支持页面使用 WebView 或 Skyline 任一模式进行渲染,Skyline 页面可以和 WebView 页面混跳,开发者可以页面粒度按需适配 Skyline。

// page.json
// skyline 渲染
{
    "renderer": "skyline"
}

// webview 渲染
{
    "renderer": "webview"
}

提供更好的性能

Skyline 在渲染流程上较 WebView 更为精简,其对节点的渲染有着更精确的控制,尽量避免不可见区域的布局和绘制,以此来保证更高的渲染性能。WebView 由于其整体设计不同以及兼容性等问题,渲染流水线的实现更加冗长复杂。

在光栅化策略上,Skyline 采用的是同步光栅化的策略,WebView 是异步分块光栅化的策略。两种策略各有千秋,但 WebView 的策略存在一些难以规避的问题,例如:快速滚动会出现白屏问题;滚动过程中的 DOM 更新会出现不同步的问题,进而影响到用户体验。

在此基础上,我们还进一步实现了很多优化点。

1. 单线程版本组件框架

Skyline 下默认启用了新版本的组件框架 glass-easel,该版本适应了 Skyline 的单线程模型,使得建树流程的耗时有效降低(优化 30%-40%),同时 setData 调用也不再有通信开销和序列化开销。

2. 组件下沉

Skyline 内置组件的行为更接近原生体验,部分内置组件(如 scroll-view、swiper 等)借助于底层实现,有更好的性能和交互体验。同时,我们将部分内置组件(如 view、text、image 等)从 JS 下沉到原生实现,相当于原生 DOM 节点,降低了创建组件的开销(优化了 30% 左右)。

3.长列表按需渲染

长列表是一个常用的但又经常遇到性能瓶颈的场景,Skyline 对其做了一些优化,使 scroll-view 组件只渲染在屏节点(用法上有一定的约束),并且增加 lazy mount 机制优化首次渲染长列表的性能,后续我们也计划在组件框架层面进一步支持 scroll-view 的可回收机制,以更大程度降低创建节点的开销。

4. WXSS 预编译

同 WebView 传输 WXSS 文本不同,Skyline 在后台构建小程序代码包时会将 WXSS 预编译为二进制文件,在运行时直接读取二进制文件获得样式表结构,避免了运行时解析的开销(预编译较运行时解析快 5 倍以上)。

5. 样式计算更快

Skyline 通过精简 WXSS 特性大幅简化了样式计算的流程。在样式更新上,与 WebView 全量计算不同,Skyline 使用局部样式更新,可以避免对 DOM 树的多次遍历。Skyline 与小程序框架结合也更为紧密,例如: Skyline 结合组件系统实现了 WXSS 样式隔离、基于 wx:for 实现了节点样式共享(相比于 WebView 推测式样式共享更为精确、高效)。在节点变更、内联样式和继承样式的更新上,Skyline 也进行了一些优化,从而保证样式计算的性能。

此外,对于 rpx 单位,我们直接在样式计算阶段原生支持,这样避免了在 JS 层面做太多额外的计算。

<!-- 样式共享目前暂未自动识别,可手动声明 list-item 属性开启 -->
<scroll-view type="list" scroll-y>
    <view wx:for="{
  {list}}" list-item>{
  {index}}</view>
</scroll-view>

6. 降低内存占用

在 WebView 渲染模式下,一个小程序页面对应一个 WebView 实例,并且每个页面会重复注入一些公共资源。而 Skyline 只有 AppService 线程,且多个 Skyline 页面会运行在同一个渲染引擎实例下,因此页面占用内存能够降低很多,还能做到更细粒度的页面间资源共享(如全局样式、公共代码、缓存资源等)。

根除旧有架构的问题

在基于 Web 体系的架构下,小程序的部分基础体验会受限于 WebView 提供的能力(特别是 iOS WKWebView 限制更大一些),使得一些技术方案无法做得很完美,留下一些潜在的问题。

1. 原生组件同层渲染更稳定

iOS 下原生组件同层渲染的原理先前有介绍过,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weifont

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值