Skip to content

小程序 ​

双线程架构 ​

  • 逻辑层和渲染层分为两个独立的线程,两者通过客户端的JSBridge进行相互通信
  • 逻辑层在ios使用自带的JSCore引擎执行,在Android使用腾讯的x5(基于blink)内核执行
  • 渲染层在ios使用自带的WKWebView进行渲染,在Android中使用腾讯的x5内核
  • JSBridge除了用于逻辑层和渲染层的通信还用于提供API以调用系统原生能力
  • 逻辑层详解
    • 提供App和Page方法作为小程序和页面的入口
    • 提供微信API使用原生的能力
    • 实现模块化能力
    • 提供数据绑定、事件分发、生命周期管理、路由管理等能力
  • 渲染层详解
    • 主要通过Exparser库实现小程序渲染的一些基础能力和组件
    • 将wxml转换成虚拟DOM,并通过虚拟DOM对比后获取最新DOM并重新渲染
    • 内置一些基础组件,包含原生和WebView的

运行机制 ​

  • 首次打开小程序或者手动刷新小程序时会进行冷启动,冷启动时微信客户端会去远程CDN上下载小程序包并进行小程序加载
  • 小程序冷启动时会执行逻辑层完整的生命周期,如onLoad等
  • 小程序关闭时会被切换至后台,在一段时间未重新使用或者内存不足时才会被销毁
  • 当短时间内再次打开关闭的小程序时,会执行小程序的热启动,直接将后台的小程序切换到前台运行
  • 小程序的热启动不会执行onLoad,只会执行onShow

渲染流程 ​

  • 初次渲染时渲染线程和逻辑线程同时进行初始化,渲染线程加载HTML、CSS和JS并完成JS的编译,逻辑线程分别加在框架和业务逻辑的JS代码并进行编译
  • 逻辑线程计算首屏DOM的结构并将初始化的数据进行序列化后通过JSBridge传给渲染线程
  • 渲染线程拿到数据后进行反序列化,执行虚拟DOM的Patch操作并进行页面渲染
  • 逻辑线程在生命周期或事件监听中进行逻辑处理,将新的数据通过setData传给渲染线程
  • 渲染线程拿到新的数据后再次进行Patch和渲染操作

基础知识 ​

  • 组件
    • 每一个组件由WXML、WXSS、JS和JSON配置文件组成
    • WXML为组件页面的模板,支持基本的循环、判断等语法,也支持模板和引入
    • WXSS为组件的样式文件,兼容CSS的大部分语法,并且提供了尺寸适配和样式引入的能力
    • JS包含组件的生命周期及逻辑处理,主要在逻辑线程执行
  • 生命周期
    • 应用的生命周期
      • onLaunch:小程序冷启动初始化完成的时候触发
      • onShow:小程序启动或者从后台切换到前台的时候执行
      • onHide:小程序被销毁或者切换至后台时执行
      • onError:小程序脚本执行错误或者API调用错误的时候执行
      • onPageNotFound:小程序页面无法找到时执行
      • onUnhandledRejection:小程序有未处理的Promise异常时执行
      • onThemeChange:系统切换主题时触发
    • 页面的生命周期
      • onLoad:页面加载的时候执行
      • onReady:页面初次渲染完成时执行
      • onShow:页面显示时执行
      • onHide:页面隐藏时执行
      • onUnload:页面卸载时执行
    • 组件的生命周期
      • created:组件创建完成时执行
      • attached:组件挂载到页面上时执行
      • ready:组件渲染完成时执行
      • moved:组件页面隐藏时执行
      • detached:组件卸载时执行
      • error:组件执行错误时执行
  • 事件
    • 事件绑定在视图层,执行在逻辑层
    • bind用于监听元素上事件,catch用于监听事件并阻止冒泡
    • bindtap为最常用的,监听点击事件的方法
    • WXS事件可以用于执行渲染层中触发较为频繁的逻辑
  • 路由
    • 小程序的路由由框架进行处理,并通过栈的形式来管理路由的页面
    • 打开新页面的时候会将该页面加入栈中,重定向或者返回上一页时会进行出栈
    • wx.navigateTo用于跳转新页面,wx.redirectTo用于重定向到新页面,wx.navigateBack用于返回页面
  • 请求
    • 小程序通过wx.request方法进行请求,在参数的回调中进行数据处理
    • 只有小程序后台配置白名单里的origin才能请求成功
  • 双向绑定
    • 可以通过 mode:value 属性对表单元素进行双向绑定
  • WXS
    • wxs相当于WXML中JS的内联实现,但和JS语法有略微不同,在视图层执行
    • 每段wxs都有独立的运行环境,可以通过module.exports和require进行导出和导入
    • 在WXML中通过wxs标签导入,类似于HTML中的script标签

业务逻辑 ​

  • 登录
    • openid:用于标识当前小程序中的唯一用户,同一个用户在不同小程序中openid不一样
    • unionid:不同小程序中同一个用户的唯一标识
    • code:用户执行小程序登录后微信提供的用户临时身份,用于后续获取用户的openid,有效期为5分钟
    • 流程
      • 前端调用wx.login方法唤起微信小程序的登录弹窗,用户登录完成之后可以拿到一个code
      • 前端通过wx.request将code发送到业务服务器,业务服务器拿到code后连通appid和appsecret一起发送给微信服务器
      • 微信服务器会将用户的openid返回给业务服务器
      • 业务服务器通过openid查询当前用户是否已经注册,若已注册则生成对应的服务器session,并将用户登录的token返回给前端
      • 由于小程序并没有Cookie和SessionStorage,所以前端可以将登录token存入到localStorage中
      • 后续请求前端从localStorage中读取并携带token发送给服务端
      • 若token失效或者用户未注册,则前端根据服务端的返回跳转对应的页面
  • 支付
    • 使用微信支付前需要先在小程序管理后台申请开通商户码
    • 用户支付完成后小程序前端是无法获悉业务服务端是否完成支付流程的,需要手动调用接口查询订单状态
    • 普通支付流程
      • 用户点击下单之后,前端调用业务服务端下单接口创建订单
      • 业务服务端生成业务订单后调用微信后台生成预付单,微信后台返回预付单信息
      • 业务服务端拿到预付单信息之后生成带签名的订单支付信息给前端
      • 前端通过订单支付信息调用wx.requestPayment接口唤起微信支付页面
      • 支付页面会调用微信后台完成支付鉴权过程,鉴权通过用户才可以输入密码支付
      • 用户支付完成后,由微信后台返回支付结果并异步的通知业务服务端
      • 前端需要在用户支付完成后调用服务端接口查询订单状态并展示支付完成的状态
    • 免密支付流程
      • 用户点击下单之后,前端调用业务服务端下单接口
      • 业务服务端向微信后台查询用户当前的授权状态
      • 若用户已授权则直接创建订单并请求微信后台创建免密支付订单
      • 若用户未授权则进入授权逻辑 * 业务服务端请求微信后台进行预授权 * 微信后台同步预授权结果并将授权需要的token等参数返回给业务服务端 * 业务服务端将参数同步给前端,前端通过参数唤起授权页面 * 用户在授权页面完成授权后由微信后台异步通知业务服务端告知授权结果
      • 订单创建完成之后业务服务端再次请求微信后台要求完结订单
      • 微信后台完结订单并通过微信支付对用户进行扣款,扣款成功后通知业务服务端和用户

动态化 ​

  • 由于小程序限制了包大小,当代码量过于庞大时会无法正常发布小程序
  • 小程序中嵌入H5为最简单的动态化技术
  • 实现小程序本身的动态化
    • 在小程序中新增动态化容器组件,该组件内置一个JSVM引擎
    • 当用户访问页面时,容器组件从CDN加载动态化后的小程序代码到本地
    • 通过JSVM执行动态化的代码并生成对应小程序页面和逻辑

小程序框架 ​

  • 运行时
    • 在小程序逻辑层实现React或者Vue的运行时,通过自定义渲染器的方式将React或Vue代码渲染为小程序页面
    • 代表框架有 mpvue、uni-app等Vue框架,以及 Taro Next、Remax等React框架
    • Vue框架
      • Vue语法本身即包含了template、style和script三部分,对应到小程序中只需要将 template 转换成小程序的 wxml,style转成wxss,script转成js即可
      • template的转换主要通过babel将模板转成ast再进行语法的匹配和变更
      • style的转换相对简单,在处理成css后可以直接作为wxss使用
      • script的部分不对用户源码进行处理,而是直接修改vue源码 * 在初始化Vue实例时调用小程序的Page方法 * vue的核心逻辑保持不变 * 将vue中的patch操作替换为小程序的setData
    • React框架
      • 在React的新架构中,支持用户自定义HostConfig协议的渲染器,可以通过此方式实现React转小程序
      • 在自定义渲染器中主要实现Fiber节点到VNode的转换以及将VNode渲染到小程序页面上的render方法 * VNode主要提供类似DOM节点的增删改方法,用于操作节点变更 * 当节点变更完成后会通过VNode树生成渲染页面需要的一个大JSON * render方法用于执行小程序的setData去更新页面中JSON对应的新数据 * 在小程序的渲染层,通过内置各种类型的template模板的方式,采用递归的方式从根template到子template进行逐一渲染
  • 编译时
    • 通过自定义的DSL,在小程序编译阶段将开发语法通过babel转换成对应的小程序语法
    • 代表框架有 Taro1/2、淘宝的Rax
    • 核心逻辑为通过babel将JSX语法转换成小程序的template,但是由于JSX语法过于灵活,导致该方式会耗费大量人力去穷举JSX语法到小程序的转换

同层渲染 ​

微信小程序的同层渲染技术是指将原生组件(如视频、地图、canvas 等)与普通的 WXML 组件(如 view、text)放置在同一渲染层中,解决了传统渲染方式中存在的层级覆盖问题,提升了交互体验和视觉一致性。

解决的问题 ​

  • 层级覆盖问题,原生组件始终在普通组件之上,无法被普通组件覆盖。
  • 交互体验问题,原生组件的事件与普通组件分离,导致滑动冲突,点击穿透等问题。

实现原理 ​

  • 原生视频(或其他原生组件)绘制到 WebView 的 Canvas 或 WebGL 上下文中,使其成为普通DOM树一部分。
  • 不直接使用webview的视频渲染,是因为webview的视频渲染会有层级覆盖问题,无法与其他DOM元素交互。还有性能问题。

Taro2 框架原理 ​

主要通过编译时将 React 代码转换为小程序的 WXML、WXSS 和 JS 代码。Taro 框架的核心原理如下:

  • 编译阶段:Taro 使用 Babel 等工具将 React 代码转换为小程序的 WXML、WXSS 和 JS 代码。
    • JSX 转换为 WXML:将 React 的 JSX 语法转换为小程序的 WXML 模板。
    • CSS 转换为 WXSS:将 CSS 样式转换为小程序的 WXSS 样式。
    • React 逻辑转换为小程序逻辑:将 React 的组件逻辑转换为小程序的 Page 或 Component 方法。
  • 运行时适配:主要是通过 Taro 提供的 API 和组件库来实现小程序的交互和功能。
    • Taro 提供了一套与小程序 API 兼容的接口,使得开发者可以使用类似 React 的方式来编写小程序。

Taro3 框架原理 ​

参考文档1参考文档2 Taro 3 则可以大致理解为解释型架构,主要通过在小程序端模拟实现 DOM、BOM API 来让前端框架直接运行在小程序环境中,从而达到小程序和 H5 统一的目的,而对于生命周期、组件库、API、路由等差异,依然可以通过定义统一标准,各端负责各自实现的方式来进行抹平。

  1. 首先用户的React和Vue的代码会进行webpack打包,然后运行时候会调用React或Vue的适配器进行适配,最后调用Taro的DOM和BOM API渲染到小程序上,。
  2. Taro 实现了taro-react 来渲染 Taro的DOM tree 。
  3. 但是小程序没提供动态创建节点的能力,Taro使用的是模板拼接的方式,根据运行时提供的DOM树结构,然后拼接成WXML字符串。

渲染为h5 ​

  • 渲染为h5,由于h5缺少小程序的规范或者组件,Taro额外做了3件事情:①实现了一个组件库,②实现了一个路由机制,③实现了类似小程序规范的API
  • 其余的逻辑基本上和框架本身的逻辑一致,主要是通过适配器将React或Vue的代码转换为Taro的DOM和BOM API。

小程序怎么收集错误 ​

错误类型 ​

  • JS 错误:逻辑层的 JavaScript 代码执行错误。
  • 渲染 错误:WXML/WXSS 渲染异常(如样式冲突、组件不存在)
  • API 调用错误:调用小程序 API 时发生的错误。
  • 性能错误:加载慢,卡顿等性能问题。

JS错误收集方式 ​

  • 全局错误监听:使用 App.onError 和 Page.onError 方法来捕获逻辑层的 JavaScript 错误。

渲染错误收集方式 ​

  • 监听 onPageNotFound 和 onUnhandledRejection:

第三方错误收集 ​

we分析、sentry

性能优化 ​

更多的小程序优化经验:点击查看