微信小程序、mpvue性能测试与体验

2023-12-11 12:36

本文主要是介绍微信小程序、mpvue性能测试与体验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近一直在折腾mpvue写的微信小程序的性能优化,分享下实战的过程。

先上个优化前后的图:

可以看到打包后的代码量从 813KB减少到 387KB,Audits体验评分从 B到 A,效果还是比较明显的。其实这个指标说明不了什么,而且轻易就可以做到,更重要的是优化 小程序运行过程中的卡顿感,请耐心往下看。
常规优化
常规的Web端优化方法在小程序中也是适用的,而且不可忽视。

一、压缩图片
这一步最简单,但是容易被忽视。在tiny上在线压缩,然后下载替换即可。

我这项目的压缩率高达 72%,可以说打包后的代码从 813KB降到 387KB大部分都是归功于压缩图片了。
二、移除无用的库
我之前在项目中使用了Vant Weapp,在static目录下引入了整个库,但实际上我只使用了button,field,dialog等几个组件,实在是没必要。

所以干脆移除掉了,微信小程序自身提供的button,wx.showModal等一些组件基本可以满足需求,自己手写一下样式也不用花什么时间。

在这里建议大家,在微信小程序中,尽量避免使用过多的依赖库。

不要贪图方便而引入一些比较大的库,小程序不同于Web,限制比较多,能自己写一下就尽量自己写一下吧。

小程序的优化
咱们首先得看一下官方优化建议,大多是围绕这个建议去做。

一、开启Vue.config._mpTrace = true
这个是mpvue性能优化的一个黑科技啊,可能大多数同学都不知道这个,我在官方文档都没有搜到到这个配置,我真的是服了。

我能找到这个配置也是Google机缘巧合下看到的,出处:mpvue重要更新,页面更新机制进行全面升级 具体做法是在/src/main.js添加Vue.config._mpTrace = true,如:

Vue.config._mpTrace = true
Vue.config.productionTip = false
App.mpType = ‘app’
复制代码
添加了Vue.config._mpTrace属性,这样就可以看到console里会打印每500ms更新的数据量。如图:

如果数据更新量很大,会明显感觉小程序运行卡顿,反之就流畅。因此我们可以根据这个指标,逐步找出性能瓶颈并解决掉。
二、精简data

  1. 过滤api返回的冗余数据
    后端的api可能是需要同时为iOS,Android,H5等提供服务的,往往会有些冗余的数据小程序是用不到的。比如api返回的一个文章列表数据有很多字段:
this.articleList = [{articleId: 1,desc: 'xxxxxx',author: 'fengxianqi',time: 'xxx',comments: [{userId: 2,conent: 'xxx'}]},{articleId: 2// ...},// ...
]

假设我们在小程序中只需要用到列表中的部分字段,如果不对数据做处理,将整个articleList都setData进去,是不明智的。

小程序官方文档: 单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。

可以看出,内存是很宝贵的,当articleList数据量非常大超过1M时,某些机型就会爆掉(我在iOS中遇到过很多次)。

因此,需要将接口返回的数据剔除掉不需要的,再setData,回到我们上面的articleList例子,假设我们只需要用articleId和author这两个字段,可以这样:

import { getArticleList } from '@/api/article'
export default {data () {return {articleList: []}}methods: {getList () {getArticleList().then(res => {let rawList = res.listthis.articleList = this.simplifyArticleList(rawList)})},simplifyArticleList (list) {return list.map(item => {return {articleId: item.articleId,author: item.author// 需要哪些字段就加上哪些字段}})}}
}

这里我们将返回的数据通过simplifyArticleList来精简数据,此时过滤后的articleList中的数据类似:

[{articleId: 1, author: 'fengxianqi'},{articleId: 2, author: 'others'}// ...
]

当然,如果你的需求中是所有数据都要用到(或者大部分数据),就没必要做一层精简了,收益不大。毕竟精简数据的函数中具体的字段,是会增加维护成本的。

PS: 在我个人的实际操作中,做数据过滤虽然增加了维护的成本,但一般收益都很大,因次这个方法比较推荐。

  1. data()中只放需要的数据
import xx from 'xx.js'
export default {data () {return {xx,otherXX: '2'}}
}

有些同学可能会习惯将import的东西都先放进data中,再在methods中使用,在小程序中可能是个不好的习惯。

因为通过Vue.config._mpTrace = true在更新某个数据时,我对比放进data和不放进data中的两种情况会有差别。

所以我猜测可能是data是会一起更新的,比如只是想更新otherXX时,会同时将xx也一起合起来setData了。

  1. 静态图片放进static
    这个问题和上面的问题其实是一样的,有时候我们会通过import的方式引入,比如这样:
<template><img :src="UserIcon">
</template>
<script>
import UserIcon from '@/assets/images/user_icon.png'
export default {data () {return {UserIcon}}
}
</script>

这样会导致打包后的代码,图片是base64形式(很长的一段字符串)存放在data中,不利于精简data。同时当该组件多个地方使用时,每个组件实例都会携带这一段很长的base64代码,进一步导致数据的冗余。

因此,建议将静态图片放到static目录下,这样引用:

<template><img src="/static/images/user_icon.png">
</template>

代码也更简洁清爽。

看一下做了上面操作的前后对比图,使用体验上也流畅了很多。

三、swiper优化
小程序自身提供的swiper组件性能上不是很好,使用时要注意。参考着两个思路:

【优化】解决swiper渲染很多图片时的卡顿
想请教一下小程序swiper组件的问题
在我使用时,由于需求原因,动态删掉swiper-item的思路不可行(手滑时会造成抖动)。因此只能作罢。但仍然可以优化一下:

将未显示的swiper-item中的图片用v-if隐藏到,当判断到current时才显示,防止大量图片的渲染导致的性能问题。
四、vuex使用注意事项
我之前写过的一篇mpvue开发音频类小程序踩坑和建议里面有讲如何在小程序中使用vuex。但遇到了个比较严重的性能问题。

  1. 问题描述
    我开发的是一个音频类的小程序,所以需要将播放列表playList,当前索引currentIndex和当前时长currentTime放进state.js中:
const state = {currentIndex: 0, // playList当前索引currentTime: 0, // 当前播放的进度playList: [], // {title: '', url: '', singer: ''}
}

每次用户点击播放音频时,都会先加载音频的播放列表playList,然后播放时更新当前时长currentTime,发现有时候播音频时整个小程序非常卡顿。

注意到,音频需每秒就得更新一次currentTime,即每秒就做一次setData操作,稍微有些卡顿是可以理解的。但我发现是播放列表数据比较多时会特别卡,比如playList的长度是100条以上时。

  1. 问题原因
    我开启Vue.config._mpTrace = true后发现一个规律:

当palyList数据量小时,console显示造成的数据量更新数值比较小;当playList比较大时,console显示造成的数据量更新数值比较大。

PS: 我曾尝试将playList数据量增加到200条,每500ms的数据量更新达到800KB左右。

到这里基本可以确定一个事实就是:更新state中的任何一个字段,将导致整个state全量一起setData。在我这里的例子,虽然我每次只是更新currentTime这个字段的值,但依然导致将state中的其他字段如playList,currentIndex都一起做了一次setData操作。

  1. 解决问题
    有两个思路:

精简state中保存的数据,即限制playList的数据不能太多,可将一些数据暂存在storage中
vuex采用Module的写法能改善这个问题,虽然使用时命名空间造成一定的麻烦。vuex传送门
一般情况下,推荐使用后者。我在项目中尝试使用了前者,同样能达到很好的效果,请继续看下面的分享。

五、善用storage
1.为什么说要善用storage
由于小程序的内存非常宝贵,占用内存过大会非常卡顿,因此最好尽可能少的将数据放到内存中,即vuex存的数据要尽可能少。而小程序的storage支持单个 key允许存储的最大数据长度为 1MB,所有数据存储上限为 10MB。

所以可以将一些相对取用不频繁的数据放进storage中,需要时再将这些数据放进内存,从而缓解内存的紧张,有点类似Windows中虚拟内存的概念。

2.storage换内存的实例
这个例子讲的会有点啰嗦,真正能用到的朋友可以详细看下。

上面讲到playList数据量太多,播放一条音频时其实只需要最多保证3条数据在内存中即可,即上一首,播放中的,下一首,我们可以将多余的播放列表存放在storage中。

PS: 为了保证更平滑地连续切换下一首,我们可以稍微保存多几条,比如我这里选择保存5条数据在vuex中,播放时始终保证当前播放的音频前后都有两条数据。

// 首次播放背景音频的方法
async function playAudio (audioId) {// 拿到播放列表,此时的playList最多只有5条数据。getPlayList方法看下面const playList = await getPlayList(audioId)// 当前音频在vuex中的currentIndexconst currentIndex = playList.findIndex(item => item.audioId === audioId)// 播放背景音频this.audio = wx.getBackgroundAudioManager()this.audio.title = playList[currentIndex].titlethis.audio.src = playList[currentIndex].url// 通过mapActions将播放列表和currentIndex更新到vuex中this.updateCurrentIndex(index) this.updatePlayList(playList) // updateCurrentIndex和updatePlayList是vuex写好的方法
}
// 播放音频时获取播放列表的方法,将所有数据存在storage,然后返回当前音频的前后2条数据,保证最多5条数据
import { loadPlayList } from '@/api/audio'
async function getPlayList (courseId, currentAudioId) {// 从api中请求得到播放列表// loadPlayList是api的方法, courseId是获取列表的参数,表示当前课程下的播放列表let rawList = await loadPlayList(courseId)// simplifyPlayList过滤掉一些字段const list = this.simplifyPlayList(rawList)// 将列表存到storage中wx.setStorage({key: 'playList',data: list})return subPlayList(list, currentAudioId)
}

重点是subPlayList方法,这个方法保证了拿到的播放列表是最多5条数据。

function subPlayList(playList, currentAudioId) {let tempArr = [...playList]const count = 5 // 保持vuex中最多5条数据const middle = parseInt(count / 2) // 中点的索引const len = tempArr.length// 如果整个原始的播放列表本来就少于5条数据,说明不需要裁剪,直接返回if (len <= count) {return tempArr}// 找到当前要播放的音频的所在位置const index = tempArr.findIndex(item => item.audioId === currentAudioId)// 截取当前音频的前后两条数据tempArr = tempArr.splice(Math.max(0, Math.min(len - count, index - middle)), count)return tempArr
}

tempArr.splice(Math.max(0, index - middle), count)可能有些同学比较难理解,需要仔细琢磨一下。假设playList有10条数据:

当前音频是列表中的第1条(索引是0),截取前5个:playList.splice(0, 5),此时currentAudio在这5个数据的索引是0,没有上一首,有4个下一首
当前音频是列表中的第2条(索引是1),截取前5个:playList.splice(0, 5),此时currentAudio在这5个数据的索引是1,有1个上一首,3个下一首
当前音频是列表中的第3条(索引是2),截取前5个:playList.splice(0, 5),此时currentAudio在这5个数据的索引是2,有2个上一首,2个下一首
当前音频是列表中的第4条(索引是3),截取第1到6个:playList.splice(1, 5) ,此时currentAudio在这5个数据的索引是2,有2个上一首,2个下一首
当前音频是列表中的第5条(索引是4),截取第2到7个:playList.splice(2, 5),此时currentAudio在这5个数据的索引是2,有2个上一首,2个下一首

当前音频是列表中的第9条(索引是8),截取后5个:playList.splice(4, 5),此时currentAudio在这5个数据的索引是3,有3个上一首,1个下一首
当前音频是列表中的最后1条(索引是9),截取后的5个:playList.splice(4, 5),此时currentAudio在这5个数据的索引是4,有4个上一首,没有下一首
有点啰嗦,感兴趣的同学仔细琢磨下,无论当前音频在哪,都始终保证了拿到当前音频前后的最多5条数据。

接下来就是维护播放上一首或下一首时保证当前vuex中的playList始终是包含当前音频的前后2条。

播放下一首
function playNextAudio() {const nextIndex = this.currentIndex + 1if (nextIndex < this.playList.length) {// 没有超出数组长度,说明在vuex的列表中,可以直接播放this.audio = wx.getBackgroundAudioManager()this.audio.src = this.playList[nextIndex].urlthis.audio.title = this.playList[nextIndex].titlethis.updateCurrentIndex(nextIndex)// 当判断到已经到vuex的playList的边界了,重新从storage中拿数据补充到playListif (nextIndex === this.playList.length - 1 || nextIndex === 0) {// 拿到只有当前音频前后最多5条数据的列表const newList = getPlayList(this.playList[nextIndex].courseId, this.playList[nextIndex].audioId)// 当前音频在这5条数据中的索引const index = newList.findIndex(item => item.audioId === this.playList[nextIndex].audioId)// 更新到vuexthis.updateCurrentIndex(index)this.updatePlayList(newList)}}
}

这里的getPlayList方法是上面讲过的,本来是从api中直接获取的,为了避免每次都从api直接获取,所以需要改一下,先读storage,若无则从api获取:

import { loadPlayList } from '@/api/audio'
async function getPlayList (courseId, currentAudioId) {// 先从缓存列表中拿const playList = wx.getStorageSync('playList')if (playList && playList.length > 0 && courseId === playList[0].courseId) {// 命中缓存,则从直接返回return subPlayList(playList, currentAudioId)} else {// 没有命中缓存,则从api中获取const list = await loadPlayList(courseId)wx.setStorage({key: 'playList',data: list})return subPlayList(list, currentAudioId)}
}

播放上一首也是同理,就不赘述了。

PS: 将vuex中的数据精简后,我所做的小程序在播放音频时刷其他页面已经非常流畅啦,效果非常好。

六、动画优化
这个问题在mpvue开发音频类小程序踩坑和建议已经讲过了,感兴趣的可以移步看一眼,这里只写下概述:

如果要使用动画,尽量用css动画代替wx.createAnimation
使用css动画时建议开启硬件加速
最后
大致总结一下上面所讲的几个要点:

开发时打开Vue.config._mpTrace = true。
谨慎引入第三方库,权衡收益。
添加数据到data中时要克制,能精简尽量精简。
图片记得要压缩,图片在显示时才渲染。
vuex保持数据精简,必要时可先存storage。
性能优化是一个永不止步的话题,我也还在摸索,不足之处还请大家指点和分享。

欢迎关注,会持续分享前端实战中遇到的一些问题和解决办法。

源码截图:

在这里插入图片描述

说明

如果本项目对您有帮助,欢迎 “点赞,关注” 支持一下 谢谢~

源码获取关注公众号「码农园区」,回复 【uniapp源码】
在这里插入图片描述

这篇关于微信小程序、mpvue性能测试与体验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/480716

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

W外链微信推广短连接怎么做?

制作微信推广链接的难点分析 一、内容创作难度 制作微信推广链接时,首先需要创作有吸引力的内容。这不仅要求内容本身有趣、有价值,还要能够激起人们的分享欲望。对于许多企业和个人来说,尤其是那些缺乏创意和写作能力的人来说,这是制作微信推广链接的一大难点。 二、精准定位难度 微信用户群体庞大,不同用户的需求和兴趣各异。因此,制作推广链接时需要精准定位目标受众,以便更有效地吸引他们点击并分享链接

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

黑神话,XSKY 星飞全闪单卷性能突破310万

当下,云计算仍然是企业主要的基础架构,随着关键业务的逐步虚拟化和云化,对于块存储的性能要求也日益提高。企业对于低延迟、高稳定性的存储解决方案的需求日益迫切。为了满足这些日益增长的 IO 密集型应用场景,众多云服务提供商正在不断推陈出新,推出具有更低时延和更高 IOPS 性能的云硬盘产品。 8 月 22 日 2024 DTCC 大会上(第十五届中国数据库技术大会),XSKY星辰天合正式公布了基于星

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测

EMLOG程序单页友链和标签增加美化

单页友联效果图: 标签页面效果图: 源码介绍 EMLOG单页友情链接和TAG标签,友链单页文件代码main{width: 58%;是设置宽度 自己把设置成与您的网站宽度一样,如果自适应就填写100%,TAG文件不用修改 安装方法:把Links.php和tag.php上传到网站根目录即可,访问 域名/Links.php、域名/tag.php 所有模板适用,代码就不粘贴出来,已经打