一直以来,小红书小程序运行时部分特性无法对齐到业界,例如小红书小程序并不支持跨多层级组件传递 functional props (多层),也不支持 triggerEvent 这类自定义组件事件冒泡和捕获行为(还有其他差异,这里暂不展开),这类差异给那些期望将小程序从其他平台迁移到小红书平台的开发者带来了一些适配成本。
造成这类差异的根本原因,是因为目前的小红书小程序架构,分离了xhsml和js模块的执行线程:渲染层负责解析和渲染xhsml,而逻辑层则维护js模块,生成自定义组件树来管理用户状态,这套架构下,渲染层和逻辑层的节点模型如图所示:
由于逻辑层没有完整的节点树且无法及时获取到父组件properties属性的变更,父子属性的变更就需要依赖渲染层的消息推送,这就导致父->子通讯的业务场景下性能降低。同时,因为依赖JSBridge进行properties父子状态传递,这就导致functional props这类属性无法被子组件获取到(function 不支持跨线程传递)。
为了进一步优化小程序性能,解决由于架构差异而导致部分能力无法与业界平台保持一致的问题,在 3.84.x 版本后,我们对架构进行了升级。在新架构下,对于属性、节点的处理将在同一线程进行处理,降低”属性变更“通讯带来的损耗,以获得更快的渲染效果。在渲染层,则依赖渲染指令进行绘制提高首屏的加载速度,新架构下,渲染层和逻辑层的节点模型如图所示:
业务代码构建阶段,我们会将 xhsml 进行编译处理。小程序启动并注入业务包后,将执行业务的JS代码。更新阶段,我们会批量收集状态变更 ,转发到渲染层进行渲染。下面是一个「数据变更 」→ 「视图刷新」的流程:
我们准备了一个 Benchmark 可帮助直观感受不同架构下, 通讯损耗和架构差异所引起的渲染性能差别
在这个 benchmark 下,我们在页面节点内,进行了多层级嵌套,完成了”父 -> 子 -> 孙“的数据 properties 传递,并在子节点下通过观察者(observers)回调当前组件实例,调用 setData 进行节点重渲染。
借助图片所演示的效果可以看到架构差异对状态传递更新带来的影响。同时,可以观察到2.0架构 renderDone 的回调耗时和渲染表现相比于1.0有较为明显的提升。