Skip to content

小程序双线程架构

双线程模型

分层介绍

x

  • 小程序的逻辑层与渲染层分离,分别运行在不同的线程上。
  • 他们之间通过系统层的 JsBridge 进行通信:逻辑层把数据变化通知到视图层,触发视图层页面更新;视图层把触发的事件通知到逻辑层进行业务处理。

渲染层(WebView)

  • 一个小程序存在多个界面,所以视图层存在多个WebView线程
  • 在 WebView 里处理 wxss/wxml

逻辑层(js Core)

  • 在 js Core 里处理 javascript

为什么要双线程模型?

web 技术存在问题

  • 体验:GUI 渲染线程与 js 逻辑线程互斥,导致一些逻辑任务抢占UI渲染的资源;这样会很慢。
  • 管控:web页面自由度很高,需要花很大的人力去检查页面是否存在违规等操作。

选择混合(Hybrid)技术

  • 界面由成熟的Web技术渲染,辅之以大量接口提供原生能力。
  • 每个小程序页面使用不用的 webview 去渲染,提供友好交互体验,更接近原生,避免单 webview 的任务过于繁重。

解决管控与安全问题

  • 为了阻止开发者使用浏览器提供的,如页面跳转、操作DOM、动态脚本等开放性问题;避免进入微信平台与开发者的攻防战
  • 为了彻底解决安全性问题,必须提供一个沙箱环境来运行开发者 js 代码。
  • 架构师视角:平台最核心的一个考量点是为案例提供足够能力的前提下,保证案例的逻辑不会危机平台的安全。

双层实现原理

双线程通信原理

  • 数据驱动理念
  • 逻辑层通过 Page 实例的 setData 方法传递数据到渲染层
  • Native 中转:逻辑层与渲染层以 Native 作为数据传输通道

渲染层

  • 数据驱动理念实践
  • WXML 结构等价与一颗 DOM 树,通过一个 JS 对象(vnode)来表达 DOM 树结构。
  • 在渲染层,宿主环境把 WXML 转换为 JS 对象,在逻辑层发生变更时,需要通过宿主环境提供的 setData 方法把数据从逻辑层传递到渲染层,把差异 apply 到原来的 DOM 树上,渲染出正确的UI 界面。

逻辑层

继续追问

为什么小程序不使用浏览器的线程模型?

  • 小程序的宿主是微信,但版本迭代是独立的
  • 小程序的定位是小而美,能力比Web差,具备微信提供的原生能力
  • 小程序可以类比为:CodePen、JSFiddle

    • CodePen 保证案例的 js 代码是 线程安全的
    • CodePen 需要禁止操作 CodePen 网站的DOM
    • CodePen 基于iframe 呈现程序效果,但不会把 js 代码完全拷贝到 iframe,而是经过一次编译流程后被注入到 iframe;基于安全考虑,编译过程中剔除一些危险代码

线程安全的其他思路?

  • Web Worker:具有线程安全特性,worker 内js不能获取 window、DOM 对象
  • Shadow DOM:是Web Components 规范的一部分,将 ShadowRoot 的模式设置为 closed,就可以禁止获取到 ShadowRoot 节点及内部DOM
  • 问题:web worker 通信性能比较差

References 1

References 2