### [手把手带你看看小程序如何优化?(实践总结)](https://www.prosaas.cn/article/16324) **Published:** 2021-12-30T02:28:40 **Author:** 5201314 **Excerpt:** 小程序如何优化?本篇文章给大家总结一下小程序优化实践,看看小程序优化项,希望对大家有所帮助!小程序运行过程我们… 小程序如何优化?本篇文章给大家总结一下小程序优化实践,看看小程序优化项,希望对大家有所帮助! ![](https://img.php.cn/upload/article/000/000/024/61cd18b9b048a707.jpg) ## **小程序运行过程** 我们先来梳理一下小程序的运行原理,磨刀不误砍柴功。 一图胜千言: ![](https://img.php.cn/upload/image/565/930/888/1640830848109444.png) 建议大家认真去理解图中的内容,对于小程序开发以及优化方向都有较有力的理论支持。 ## **优化项** **1\. 合理的使用分包** 微信小程序的主要特点是启动快速,为了这一特性,官方因此限制了包的大小,上限为 2M。 分包是小程序优化的第一要务,能有效提高小程序启动速度,以及页面打开速度。 包分为【主包】【普通分包】【独立分包】。 【主包】应该只放置启动页或者**TabBar**页面。 【普通分包】放置非**TabBar**页面的其他页面,推荐按照页面数量或者模块划分多个分包,减少分包的大小,当用户进入对应分包页面的时候才会去下载这个包,这也实现了包的按需加载,避免了资源浪费。当小程序从普通分包中的某个页面的时候启动时,需要首先下载主包,然后在下载分包。 【独立分包】放置一些独立性较高的页面,当小程序从独立分包中的页面启动时,只会下载独立分包,从而大大提高小程序启动速度,当用户进入**TabBar**页面或者其他普通分包页面才回去下载对应的包。 > 独立分包中不能有任何全局的东西,包括组件,登录等,引入任何其他包中的资源都会出错。 **作者建议**梳理好页面和功能再分包,分包的界限并不是包的大小超过了 **2M**,而是要灵活的根据**业务和功能**来进行划分。在如今正常网络情况下,**2M** 的分包和 **500KB** 的分包的下载可能用户感知差距不会特别大,但是如果是在弱网环境下,这两者会造成用户白屏的时间上就有很大的差距(亲身经历,可以说是掏心掏肺了)。 > _比如,我会将那些可以由**TabBar**页面直接进入且频率较高的二级页面放入一个分包,然后其他更深层次的页面或者那些不是那么重要的页面分成一个包,又或者将整个订单业务模块的页面分成一个包。_ 包分好了,自然不能少了【分包预下载】。可以按照官网的规则进行配置,当用户进入某个页面时,提前下载包。 **2\. 按需注入** 小程序下载完包之后,会将打开页面所在包的全部`JS`合并注入,一些未访问的页面以及未用到的自定义组件也会被注入到运行环境当中。影响注入耗时和内存占用。我们希望的是当包下载完成后,只注入我们即将打开的页面的代码就行。 > 这也是小程序启动或跳转进入分包页面影响白屏时间的一点。 { "lazyCodeLoading" : "requiredComponents" } **3\. 明确 `setData` 的几个调用原则** 小程序是以微信客户端为宿主运行的,即`wxml`、`wxs`、`wxss`都是运行在客户端的,运行环境又分成了两个线程,一个渲染线程,一个逻辑线程。渲染层使用 `WebView` 进行渲染, 逻辑层使用`JSCore`运行`JS`代码。`wxml`和`wxss`工作在渲染线程,而`wxs`工作在逻辑线程。那两个线程之间怎么通信呢? - **通过客户端作为中转站进行通信** 渲染层触发事件响应到客户端,逻辑层通过setData传送数据到客户端,两边的数据都会被转换成字符串之后进行传输,客户端再分别做出响应,并且响应并非实时的。意味着在逻辑层触发`setData`页面并不会马上更新,会有一些延迟渲染层才会更新。 模型如图: ![](https://img.php.cn/upload/image/820/717/335/1640830856789293.png) `Native`即客户端。 回到问题,`setData`在逻辑层调用,让渲染层快速响应取决于逻辑层到客户端的数据传输效率,而这个传输效率又取决于你传输数据的大小,所以在调用`setData`的时候应该尽可能减少数据传输大小。 `Native`会将`wxml`转换成 **js对象**,然后和`setData`传进来的对象做差异化对比,将差异化渲染到视图上。 综上原理,我们调用`setData`应该遵循几个原则: - 尽可能减小需要 **setData** 数据的大小,**`JSON.stringify`后不超过 256KB**。 - 避免将不需要渲染的数据(不在`wxml`中绑定的数据)传入`setData`,减少差异对比耗时。 - 避免过于频繁调用`setData`,会导致逻辑层业务繁忙,一直在处理`setData`的传输队列,而导致抽不开身去处理渲染层的响应,从而导致渲染阻塞,页面出现卡顿,甚至`setData`无效。如果可以的话,可以采用节流等方式进行优化。 - 尽可能将多个需要更新的数据合并为一次`setData`,减少通信过程。 - 避免后台页面触发`setData`,也会占用Js线程,有可能会造成阻塞,导致真正需要`setData`的数据没有响应 减小`setData`的数据大小通常在列表场景中,通常只更新需要更新的下标: const needRefresh = \`list\[${index}\]\` // 写法一 setData({ \[needRefresh\]: '新值' }) // 写法二 setData({ \[\`list\[${index}\]\`\]: '新值' }) // 写法三 setData({ 'list\[0\]': '新值' }) // 写法四 const needRefresh = \`list\[${index}\].disabled\` setData({ \[needRefresh\]: '新值' }) // 写法5 更新对象 setData({ 'personal.name':'xxx' }) > 如果有变量,就需要放在`[]`内。 **4\. 控制图片大小比例** > 图片太大会增加下载时间和内存的消耗,并且为了用户体验,应该控制图片的高宽比例,防止图片变形或者被裁切(这个问题可以根据`image`的`mode`属性进行调整)。 一个合格的图片应该满足以下两点: - **图片宽高乘积 <= 实际显示宽高乘积 \* (设备像素比 ^ 2)**。 - **显示的高/宽与原图的高/宽不超过 15%**。 由于这些图片都出自 **UI**,所以在这一条优化上你需要做的是:拿着这两条指标去跟 **UI** battle。 good lucky ~ 以上第一条就是和设备的【**dpr**】相关,移动端开发一定要理解【**dpr】,这里就不多赘述了**。 我们应该合理的采用图片资源,例如在【**dpr**】为 2 的设备上,一个 **60x60** 的元素区域显示的图片为了兼顾清晰度与资源大小,图片大小不应该超过 **120x120**, 同理,【**dpr**】为 3 设备,图片应该不超过 **180x180。** 我们小程序的资源都放在**cdn**上,可以利用**cdn**的图片云处理功能对资源请求进行控制,我司用的七牛云和又拍云,如下: // 七牛云 \`${\_src}?imageMogr2/thumbnail/!${scaleRatio}p\` // 又拍云 \`${\_src}!/scale/${scaleRatio}\` 更多云处理功能可以挪步官网:七牛云(https://developer.qiniu.com/dora/8255/the-zoom) 和又拍云(https://help.upyun.com/knowledge-base/image/) 我们在小程序内自定义了图片组件 `cus-image` , 该组件会根据【**dpr**】对图片进行云处理。并提供了 `ratio` 属性灵活调整图片大小(因为运营方上传的图片可能在不同尺寸的元素区域内引用,所以需要开发人员灵活控制)。 **5\. 避免短时间内发起太多请求** 小程序中`wx.request`、`wx.uploadFile`、`wx.downloadFile`的发起的网络请求短时间内最大并发限制是 **10** 个,超过 **10** 个就会导致请求阻塞。而图片请求的并发最大数量为**6**。 那**短时间**怎么去界定呢? - 【网络请求】**耗时超过 300ms 的请求并发数不超过 10 个**(一般不会出现这个问题,如果有这个问题那可能该考虑拆分页面、拆分业务或者合并接口了。) - 【图片请求】**同域名耗时超过 100ms 的图片请求并发数不超过 6 个** 例如:**300ms**内发送了12个请求,其中10个请求在**300ms**内就请求完成了,只有2个请求超过300ms,这样是没有问题的。 【解决方案】 - 在接口请求上我们应该尽可能的减少请求数量。 - 图片可以设置懒加载`lazy-load`。 - 图标可以使用雪碧图。 - 将图片资源拆分在多个域名下。 - 自定义一个分片处理函数,将请求拆分成数个阶段发出。 function interelTasks(task,wait){ this.data.timer = setInterval(()=>{ task() }, wait) } async function task(promiseList = \[\]){ const result = await promise.all(promiseList) // do something } > 叨扰一句:有些时候在请求数量限制范围内,我们应该对没有先后顺序的接口进行并发处理,提高接口处理效率。 **6\. 请求耗时优化** 这一点主要体现在两个方面——【接口】和【静态资源】。 【接口】基本上不应该超过**1000ms**,哪怕是几百毫秒也可能需要做一些优化了,基本上正常速度在**10-200ms**,个别接口几百也正常,大部分都应该不超过**500ms**(后端大佬请消消气)。 【静态资源】首先从资源的**大小**考虑出发,大部分资源是图片,可以参考上面的图片大小标准。其次考虑**资源缓存**,对于小程序而言,静态资源基本上是存放在**cdn**上的,设置缓存可以有效的提高客户端表现性能。 这边给大家分享一个图片压缩网站:https://tinypng.com/ **7\. 避免使用过大的 WXML 节点数目** > 建议一个页面使用少于 1000 个 WXML 节点,节点树深度少于 30 层,子节点数不大于 60 个。一个太大的 WXML 节点树会增加内存的使用,样式重排时间也会更长,影响体验。 页面的节点数包含所有子节点数,需要注意的是子节点数,若一个子节点数大于60的时候,或许你就该考虑对组件或者页面进行重新划分了。 基本功! **8\. 使用骨架屏** 骨架屏相信大家都不陌生,如果我们的优化手段都用尽了,页面需要加载的资源本身就比较多,那骨架屏也是我们退而求其次的最佳方案了,也算是“曲线救国“了。 实现骨架屏的方式有多种,你可以自己写一个骨架组件,也可以用一些生成骨架屏的插件。除此之外,小程序还提供了白嫖方案,开发者工具提供了自动生成骨架屏代码的能力。 > 详情请访问 https://developers.weixin.qq.com/miniprogram/dev/devtools/skeleton.html **9\. 合理的进行组件拆分并减小`data`的大小** 微信小程序的更新是基于组件的,自定义组件的更新只会在组件内部,这能减少差异比较带来的耗时。 控制`data`的大小主要是为了减少内存消耗,比如在`data`中定义一些图片路径的变量,如果可以,我更推荐通过`background`的方式去加载一些图片。 **10\. 滚动区域设置惯性滚动** 惯性滚动会使滚动比较顺畅,在安卓下默认有惯性滚动,而在 iOS 下需要额外设置 `-webkit-overflow-scrolling: touch` 的样式。 **11\. 扩大点击元素的可点击区域** 微信规定最小可点击区域应该不小于 **20x20** 像素。这种样式问题不多赘述了,八仙过海,各显神通。 ## **最后** 性能优化不是一个技术债务,而是需要我们在平时的迭代版本中去不断的优化或重构,团队中的成员都应该明确这一点。 > 性能优化不仅仅是前端的事情,是需要团队中各个不同的职责相互配合才能做好的事情,所以,如果你发现接口慢,图片大,请勇敢的提出来,并和你的同事沟通解决。事无巨细,都很重要。 还有一些更细节的优化点可以参考官网地址: - https://developers.weixin.qq.com/miniprogram/dev/framework/audits/audits.html 如果有什么问题欢迎留言指正。 【相关学习推荐:小程序开发教程】 以上就是手把手带你看看小程序如何优化?(实践总结)的详细内容,更多请关注知企PROSAAS其它相关文章! **Tags:** background, html, https, ios, JS, json, overflow, ui, webkit, webview **Categories:** 后端开发 ---