聊聊小程序原理分析🌟

420 阅读8分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

小程序开发的模式与 Web 开发类似,使用 JavaScript 进行开发,使用 CSS 控制样式,最终使用 HTML 进行渲染。但是,我们开发的小程序的 JS 代码,其实是运行在一个被称为“逻辑层”的独立运行环境中(大多数情况下),并且每个小程序有且仅有一个“逻辑层”。

在 Web 开发中,每个页面中 JS 线程与渲染线程是互斥的;而在小程序中,JS 的运行进程与渲染进程(视图层)是独立的,视图的渲染更新,并不会阻塞 JS 的执行,同时 JS 的逻辑执行,也不会阻塞视图的渲染更新。

image.png

1、小程序的双线程设计:

小程序分为渲染层(由webView线程管理)和逻辑层(由客户端JavaScript解释引擎线程管理) 双线程设计优点:

  • 可以防止恶意攻击者xss攻击;

  • 可以防止开发者恶意盗取用户敏感信息;

  • 提升页面加载性能; 1.webview:是一个嵌入式的浏览器,是嵌入在原生应用中的,用来展示网页的 view 组件,webview 是手机中内置了一款高性能 webkit 内核浏览器,在 SDK 中封装的一个组件。页面得载入是通过创建并插入webview来实现的。

    2.Native:底层基础库、Service等都是事先放在Native层中的,当页面进行加载的时候再进行动态的注入,还负责请求的转发,离线存储,组件渲染等,Native层统一控制路由。

内置组件有一部分较复杂组件是用客户端原生渲染的,以提供更好的性能

JsCore:javaScript 的解释引擎(在iOS下使用内置的 javaScriptCore框架,在安卓则是用腾讯x5内核提供的JsCore环境),可以创建一个单独的线程去执行 javaScript

提供沙箱环境来运行开发者的JavaScript 代码,为了安全,这是避免js访问任何浏览器api。

注意事项:

1.微信/飞书小程序做了限制,在微信小程序中打开的页面不能超过10个,达到10个页面后,就不能再打开新的页面,如果不做限制,会有严重的内存问题。

2.在执行wx.navigateTo新开一个页面的时候,就是创建一个新的webview并插入到视图层中,这就是在微信小程序中从右往左划出来的一个页面的原因。

2、小程序的渲染过程:

渲染层渲染过程:

  1. 初始渲染:初始渲染时,将初始数据套用在对应的wxml片段上生成节点数
  2. 初始渲染中得到的data和当前节点树会保留下来重渲染

页面渲染:在小程序启动前,会提前准备好一个页面层级用于展示小程序的首页。除此以外,每当一个页面层级被用于渲染页面,微信都会提前开始准备一个新的页面层级,使得每次调用navigateTo都能够尽快展示一个新的页面。
数据渲染:

一、data是页面第一次渲染使用的初始数据。页面加载的时候,data将会以JSON字符串形式由逻辑层传至渲染层。

二、渲染层和逻辑层同时开始初始化,渲染层初始化完毕后会发出信号,发出一个我已经初始化完毕的信号发给逻辑层,并且自身状态进入等待。逻辑层收到这个信号的时候有两种情况:
1. 逻辑层还没初始化完,那么收到此信号后只需要初始化完毕后发送初始数据Data到渲染层即可。
2. 逻辑层早已经进入等待状态,那么收到信号后立即发送初始数据Data到渲染层即可。

3、什么是shadow Tree:

Web components的一个重要属性封装:可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更干净、整洁 Web components中的三项技术:

  • Custom element(自定义元素)
  • Shadow DOM(影子DOM)
  • HTML template模板

PS:影子DOM,粉色部分被隐藏
微信小程序的设计中就借鉴了shadowDOM这种结构。

4、小程序的启动过程:

在小程序启动前,微信会提前准备好一个页面层级用于展示小程序的首页,页面层级的准备工作分为三个阶段:

  1. 第一阶段是启动一个WebView,在iOS和Android系统上,操作系统启动WebView都需要一小段时间。
  2. 第二阶段是在WebView中初始化基础库,此时还会进行一些基础库内部优化,以提升页面渲染性能。
  3. 第三个阶段是注入小程序WXML结构和WXSS样式,使小程序能在接收到页面初始数据之后马上开始渲染页面

小程序每个视图层页面内容都是通过pageframe.html模板来生成的,包括小程序启动的首页;

接着来看看小程序为快速打开小程序页面做的技术优化:

  • 首页启动时,即第一次通过pageframe.html生成内容后,后台服务会缓存pageframe.html模板首次生成的html内容。
  • 非首次新打开页面时,页面请求的pageframe.html内容直接走后台缓存。
  • 非首次新打开页面时,pageframe.html页面引入的外链js资源走本地缓存。

PS:所以小程序提测阶段记得清缓存哦~

小程序启动分为两种情况:

  • 冷启动:如果用户首次打开、或者小程序销毁后被用户再次打开,此时小程序需要重新加载启动。
  • 热启动:如果用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时小程序并未被销毁,只是从后台状态进入前台状态。

只有当小程序进入后台一段时间,或者系统资源占用过高,才会被销毁。

5、小程序的更新机制:

  1. 未启动时更新:
  • 本地有小程序的历史版本:可能打开旧版本
  • 客户端检查本地缓存:有新版本会静默更新
  • 发布之后24小时之内:下发新版本到用户
  1. 启动时更新:
  • 小程序每次冷启动:检查是否有更新版本
  • 有版本:异步下载新版本,同时启动本地包
  • 新版本需要等下一次冷启动才会应用上

6、生命周期相关:

navigateTo方式是创建新的webview,并且展示新的webview,当前webview进入隐藏状态,这时,并未进行页面卸载;

redirectTo以及navigateBack是通过更新自身webview进行页面转换的,所以当前页面会进行卸载操作,并且重新生成新页面。所以两个页面都会进入完整生命周期序列。

7、小程序的路由机制:

webview的添加或删除都会有一个载体来维护,这就是路由栈。

注意事项:打开新页面就会往路由栈上方推入一个页面,删除则从栈顶依次删除。

并且webview不可以无限插入,因为这种多页面形式会有性能问题,所以路由栈有最大的插入限制,最多回退到首页。

小程序中的路由栈变化:

  • 小程序初始化的时候需要推入首页,新页面入栈。
  • 打开新页面对应 navigateTo,新页面入栈
  • 页面重定向 redirectTo,当前页面出栈,而后新页面入栈。
  • 页面回退 navigateBack,页面一直出栈,到达指定页面停止。
  • Tab切换 switchTab,页面全部出栈,只留下新的Tab页面。
  • 重新加载 reLaunch,页面全部出栈,只留下新的页面。

8、小程序的分包加载机制:

在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包的小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。

  1. 在小程序启动时,会根据启动页面加载对应的包:
  • 当启动页面是主包内的某个页面时,会流加载主包并启动主包内页面;
  • 当启动页面是普通分包内的某个页面时,客户端会把对应分包和主包下载下来,下载完成后启动普通分包的页面;
  • 当启动页面是独立分包内的某个页面时,客户端会流加载独立分包并启动独立分包的页面;
  1. 目前小程序分包大小有以下限制:
  • 整个小程序所有分包大小不超过 16M;
  • 单个主包大小不能超过 4M;
  • 单个分包大小不能超过 2M;

以上为目前的数据,未来数据会更新

对小程序进行分包,可以优化小程序首次启动的下载时间。

有bug?想补充?

感谢大家观看这篇文章,有任何问题或想和我交流,请直接留言,

发现文章有不妥之处,也可指出交流,感谢阅读~

53875b26-8251-4ccc-ad02-70badf65d662.gif