开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
小程序开发的模式与 Web 开发类似,使用 JavaScript 进行开发,使用 CSS 控制样式,最终使用 HTML 进行渲染。但是,我们开发的小程序的 JS 代码,其实是运行在一个被称为“逻辑层”的独立运行环境中(大多数情况下),并且每个小程序有且仅有一个“逻辑层”。
在 Web 开发中,每个页面中 JS 线程与渲染线程是互斥的;而在小程序中,JS 的运行进程与渲染进程(视图层)是独立的,视图的渲染更新,并不会阻塞 JS 的执行,同时 JS 的逻辑执行,也不会阻塞视图的渲染更新。
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、小程序的渲染过程:
渲染层渲染过程:
- 初始渲染:初始渲染时,将初始数据套用在对应的wxml片段上生成节点数
- 初始渲染中得到的data和当前节点树会保留下来重渲染
数据渲染:
一、data是页面第一次渲染使用的初始数据。页面加载的时候,data将会以JSON字符串形式由逻辑层传至渲染层。
二、渲染层和逻辑层同时开始初始化,渲染层初始化完毕后会发出信号,发出一个我已经初始化完毕的信号发给逻辑层,并且自身状态进入等待。逻辑层收到这个信号的时候有两种情况:
1. 逻辑层还没初始化完,那么收到此信号后只需要初始化完毕后发送初始数据Data到渲染层即可。
2. 逻辑层早已经进入等待状态,那么收到信号后立即发送初始数据Data到渲染层即可。
3、什么是shadow Tree:
Web components的一个重要属性封装:可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更干净、整洁 Web components中的三项技术:
- Custom element(自定义元素)
- Shadow DOM(影子DOM)
- HTML template模板
微信小程序的设计中就借鉴了shadowDOM这种结构。
4、小程序的启动过程:
在小程序启动前,微信会提前准备好一个页面层级用于展示小程序的首页,页面层级的准备工作分为三个阶段:
- 第一阶段是启动一个WebView,在iOS和Android系统上,操作系统启动WebView都需要一小段时间。
- 第二阶段是在WebView中初始化基础库,此时还会进行一些基础库内部优化,以提升页面渲染性能。
- 第三个阶段是注入小程序WXML结构和WXSS样式,使小程序能在接收到页面初始数据之后马上开始渲染页面
小程序每个视图层页面内容都是通过pageframe.html模板来生成的,包括小程序启动的首页;
接着来看看小程序为快速打开小程序页面做的技术优化:
- 首页启动时,即第一次通过pageframe.html生成内容后,后台服务会缓存pageframe.html模板首次生成的html内容。
- 非首次新打开页面时,页面请求的pageframe.html内容直接走后台缓存。
- 非首次新打开页面时,pageframe.html页面引入的外链js资源走本地缓存。
PS:所以小程序提测阶段记得清缓存哦~
小程序启动分为两种情况:
- 冷启动:如果用户首次打开、或者小程序销毁后被用户再次打开,此时小程序需要重新加载启动。
- 热启动:如果用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时小程序并未被销毁,只是从后台状态进入前台状态。
只有当小程序进入后台一段时间,或者系统资源占用过高,才会被销毁。
5、小程序的更新机制:
- 未启动时更新:
- 本地有小程序的历史版本:可能打开旧版本
- 客户端检查本地缓存:有新版本会静默更新
- 发布之后24小时之内:下发新版本到用户
- 启动时更新:
- 小程序每次冷启动:检查是否有更新版本
- 有版本:异步下载新版本,同时启动本地包
- 新版本需要等下一次冷启动才会应用上
6、生命周期相关:
navigateTo方式是创建新的webview,并且展示新的webview,当前webview进入隐藏状态,这时,并未进行页面卸载;
redirectTo以及navigateBack是通过更新自身webview进行页面转换的,所以当前页面会进行卸载操作,并且重新生成新页面。所以两个页面都会进入完整生命周期序列。
7、小程序的路由机制:
webview的添加或删除都会有一个载体来维护,这就是路由栈。
注意事项:打开新页面就会往路由栈上方推入一个页面,删除则从栈顶依次删除。
并且webview不可以无限插入,因为这种多页面形式会有性能问题,所以路由栈有最大的插入限制,最多回退到首页。
小程序中的路由栈变化:
- 小程序初始化的时候需要推入首页,新页面入栈。
- 打开新页面对应 navigateTo,新页面入栈
- 页面重定向 redirectTo,当前页面出栈,而后新页面入栈。
- 页面回退 navigateBack,页面一直出栈,到达指定页面停止。
- Tab切换 switchTab,页面全部出栈,只留下新的Tab页面。
- 重新加载 reLaunch,页面全部出栈,只留下新的页面。
8、小程序的分包加载机制:
在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包的小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。
- 在小程序启动时,会根据启动页面加载对应的包:
- 当启动页面是主包内的某个页面时,会流加载主包并启动主包内页面;
- 当启动页面是普通分包内的某个页面时,客户端会把对应分包和主包下载下来,下载完成后启动普通分包的页面;
- 当启动页面是独立分包内的某个页面时,客户端会流加载独立分包并启动独立分包的页面;
- 目前小程序分包大小有以下限制:
- 整个小程序所有分包大小不超过 16M;
- 单个主包大小不能超过 4M;
- 单个分包大小不能超过 2M;
以上为目前的数据,未来数据会更新
对小程序进行分包,可以优化小程序首次启动的下载时间。
有bug?想补充?
感谢大家观看这篇文章,有任何问题或想和我交流,请直接留言,
发现文章有不妥之处,也可指出交流,感谢阅读~