微信小程序性能优化

embedded/2024/12/26 12:02:04/

性能优化是任何应用开发中的重要组成部分,尤其是在移动环境中。对于微信小程序而言,随着用户量的增加和应用功能的丰富,性能优化显得尤为关键。良好的性能不仅提升用户体验,还能增加用户留存率和应用的使用频率。我们将探讨如何在微信小程序中进行性能优化,涵盖从首屏加载、分包、网络请求到渲染性能等多个方面。

  • 网络请求:合并请求,减少HTTP请求次数;使用缓存策略减少重复请求。
  • 布局与样式:避免使用复杂的CSS选择器;合理使用Flex布局减少重排重绘。
  • 事件处理:移除不再需要的事件监听器,防止内存泄漏。
  • 组件懒加载、按需加载

一、优化首屏加载

1. 减少初始包的体积

每个小程序都有一个加载包,包含了代码及依赖。为了加快加载速度,我们应尽量减少包的体积。

  • 懒加载组件:在小程序中使用 Component 时,可以选择懒加载。只有在组件实际需要时再加载。

    Component({properties: {show: {type: Boolean,value: false}},observers: {'show': function (newVal) {if (newVal) {// 只在需要展示时加载相关资源require('./path/to/your/component.js');}}}
    });
    
  • 拆分代码:把代码拆分成多个小模块,按需加载。
    合理地分割代码模块,不仅可以使代码结构更加清晰,还能够提高加载效率。只加载用户当前需要的部分,避免一次性加载整个应用的所有代码。

    // 示例:按需加载
    const pages = {home: () => import('./pages/home'),about: () => import('./pages/about')
    };Page({onLoad: function() {// 根据需要动态加载页面pages.home().then(module => {module.default.loadContent();});}
    });
    
  • 资源懒加载:按需加载图片和其他资源,减少初始加载时间。

    <image src="" mode="widthFix" data-src="{{item.image}}" bindload="imageLoad"/>// JS部分
    imageLoad(e) {e.currentTarget.src = e.currentTarget.dataset.src;
    }
    
  • 资源复用:合理利用已有资源减少重复加载

    对于那些多次使用的资源,如图标、背景等,我们可以将其作为公共资源存储起来,避免在每次加载页面时重复下载。

    // 示例:将公共图标作为公共资源
    const icons = ['icon1.png', 'icon2.png'];function preloadIcons() {icons.forEach(icon => {const img = new Image();img.src = icon;});
    }preloadIcons();
    

2. 资源压缩与图片优化

  • 图片格式与大小:使用合适的格式,如 JPEG、PNG 或 WEBP。尽可能减小图片尺寸,以减少加载时间。借助工具压缩图片,减少图片大小,同时保持较高质量。
  • 使用云存储:将图片存储在云端,利用 CDN 加速加载。
  • 代码压缩和混淆
    利用构建工具(如webpack)进行代码压缩和混淆,减小包体积,提高加载速度。
    // webpack.config.js
    module.exports = {mode: 'production',optimization: {minimize: true,},
    };
    

3. 优化 CSS 和 JavaScript

  • 减少 CSS 选择器的复杂性:复杂的选择器会增加渲染时间,建议使用简短的类名和 ID。
  • 合并 CSS 文件:将多个 CSS 文件合并成一个,减少 HTTP 请求次数。
  • 使用 CSS3 动画:使用 CSS3 动画替代 JavaScript 动画,控制性能和流畅度。

二、网络请求优化

网络请求是小程序性能的另一个关键因素,优化网络请求可以显著提升用户体验。

1. 缓存机制

使用缓存机制可以减少数据重复请求,加速数据的获取。

  • 使用 wx.setStorageSync 和 wx.getStorageSync:在获取数据后将其存储到本地,以后请求前先检查本地是否已有缓存。
const fetchData = async () => {const cachedData = wx.getStorageSync('myData');if (cachedData) {return cachedData; // 使用缓存}const response = await wx.request({/*...*/});wx.setStorageSync('myData', response.data);return response.data;
};

2. 限制请求数量

避免在短时间内发送过多请求,可以合并请求或使用防抖和节流技术。

  • 防抖

    let debounceTimer;
    function debounce(func, delay) {return function (...args) {clearTimeout(debounceTimer);debounceTimer = setTimeout(() => func.apply(this, args), delay);};
    }// 使用示例
    const fetchDataDebounced = debounce(fetchData, 300);
    
  • 节流

    function throttle(func, limit) {let lastFunc;let lastRan;return function () {const context = this;const args = arguments;if (!lastRan) {func.apply(context, args);lastRan = Date.now();} else {clearTimeout(lastFunc);lastFunc = setTimeout(() => {if (Date.now() - lastRan >= limit) {func.apply(context, args);lastRan = Date.now();}}, limit - (Date.now() - lastRan));}};
    }
    

3. 分批加载:避免一次性加载大量数据

当需要加载大量数据时,可以采用分批加载的方式,每次只加载一部分数据,待这部分数据处理完毕后再加载下一批。

// 示例:分批加载数据
function fetchBatchData(page) {wx.request({url: `https://api.wwww.com/data?page=${page}`,success: function(res) {const newData = res.data;// 处理数据this.setData({items: this.data.items.concat(newData)});}});
}fetchBatchData(1);

4. 智能请求:根据网络状况调整请求策略

根据用户的网络环境动态调整请求策略,可以进一步提高数据加载的速度和成功率。

// 示例:根据网络状况调整请求策略
wx.getNetworkType({success: function(res) {const networkType = res.networkType;if (networkType === '2g') {// 在2G网络环境下减少请求次数fetchBatchData(1, 5); // 一次性请求5页数据} else {// 其他网络环境下正常请求fetchBatchData(1);}}
});

三、优化页面渲染性能

页面渲染效率直接影响用户体验,优化渲染性能是非常必要的。

1. 启动速度优化 

  • 减少全局数据初始化
  • 使用分包加载,将不常用页面分割到子包中

2. 使用 wx:if 和 wx:for

适当使用 wx:if 和 wx:for(使用wx:key优化列表渲染) 避免过多的视图层重绘。尽量使用 wx:show 替代 wx:if,因为 wx:if 会在条件变化时销毁和重新创建节点。

3. 合理使用数据绑定

在数据大规模更新时,避免一次性改变全部数据,使用 this.setData() 时要尽量精简,减少触发视图的重复渲染。

this.setData({'todos[0].completed': true // 只更新部分数据
});

4. 使用组件化

将页面拆分成多个小组件,每个组件负责各自的状态和渲染,这样可以有效地减少失去控制的渲染过程,增加性能。同时也提高了代码的可维护性。

5. 避免长任务

对长时间运行的任务进行拆分,避免在主线程中阻塞 UI 更新。可以使用 Promise 和 setTimeout 进行分步执行,确保 UI 不被冻结。

6. 内存管理

  • 监听页面生命周期,及时释放不再使用的资源
  • 使用WeakRef避免循环引用问题
onUnload() {// 清理定时器、监听器等this.timer && clearInterval(this.timer);
}

7. 削减冗余:识别与移除无用代码

删除冗余代码就像是给程序减肥,让它变得更加苗条。那些不再使用的函数、未引用的变量或者废弃的样式都应该被清理掉,这样才能保证小程序运行得更快。

// 示例:删除未使用的变量
let unusedVar = 'I will be removed'; // 不再使用此变量function cleanUpCode() {// 删除未使用的变量delete unusedVar; // 实际开发中应使用工具或手动检查
}cleanUpCode();

8. 异步处理:合理使用异步任务不阻塞主线程

合理使用异步任务可以避免阻塞主线程,从而提高程序的执行效率。

// 示例:使用Promise异步加载数据
function fetchDataAsync() {return new Promise((resolve, reject) => {wx.request({url: 'https://api.wwww.com/data',success: resolve,fail: reject});});
}fetchDataAsync().then(res => {this.setData({items: res.data});
});

9. 动画优化:流畅过渡增强交互感

通过优化动画效果,可以使用户界面更加流畅,增强用户的交互体验。

// 示例:优化动画效果
Page({data: {animate: false},startAnimation: function() {this.setData({animate: true});setTimeout(() => {this.setData({animate: false});}, 1000);}
});

四、减少小程序的启动时间

1. 初始页面优化

在小程序启动时载入的页面要尽量简化,减少初始页面的内容,延迟加载不必要的内容。

2. 使用 wx.navigateTo 与 wx.redirectTo

合理使用页面跳转方式,避免使用 wx.redirectTo 后缀跳转过多的页面,而导致栈溢出,减慢响应速度。

五、工具与监控

1. 性能监控工具

使用微信开发者工具中的性能分析工具来监控小程序的性能,查看每个调用的时间,找出性能瓶颈。

2. 代码性能分析

使用一些 JavaScript 的代码静态分析工具(如 ESLint, Prettier)来确保代码的高效性,及时优化掉低效代码。

六、优化微信小程序超包问题

1. 分包

分包部分规则
1、子包最多100个
2、tabBar页面只能在主包中
3、子包内不能再分包
4、子包内的资源不能互相引用(可使用分包异步化解决),但可使用主包内的资源
5、整个小程序所有分包大小不超过 20M,单个分包/主包大小不能超过 2M
小程序开发者工具的代码依赖分析可以查看包体积情况

分包规则

// 在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,会把对应分包自动下载下来,下载完成后再进行展示,此时终端界面会有等待提示。
{// pages 主包(默认启动页面及 TabBar 页面)"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages{// 页面上访问路径 /pages/index/index"path": "pages/index/index","style": {"navigationBarTitleText": "首页",// custom即取消默认的原生导航栏"navigationStyle": "custom","navigationBarTextStyle": "white"// "enablePullDownRefresh":false, //是否允许底部下拉刷新,可在页面配合 onPullDownRefresh生命周期一起使用}},{"path": "pages/my/my","style": {"navigationBarTitleText": "我的","navigationStyle": "custom","navigationBarTextStyle": "white"}},{"path": "pages/cart/cart","style": {"navigationBarTitleText": "购物车"}},{"path": "pages/404/404","style": {"navigationBarTitleText": "页面未找到","enablePullDownRefresh": false}}],"globalStyle": {"navigationBarTextStyle": "black","navigationBarTitleText": "uni-app","navigationBarBackgroundColor": "#F8F8F8","backgroundColor": "#F8F8F8"},// 组件自动引入规则// easycom方式引入组件不是全局引入,而是局部引入。例如在H5端只有加载相应页面才会加载使用的组件"easycom": {// 是否开启自动扫描"autoscan": true,"custom": {// uni-ui 规则如下配置  uni扩展组件"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",//以 Xtx 开头的组件,匹配components目录内的vue文件(需要重启服务器)"^Xtx(.*)": "@/components/Xtx$1.vue"// 匹配node_modules内的vue文件,如匹配 uview-ui 包的组件// "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"}},// 底部"tabBar": {"color": "#333","selectedColor": "#27ba9b","backgroundColor": "#fff","borderStyle": "white","list": [{"text": "首页",// pagePath要与上面的pages一致"pagePath": "pages/index/index","iconPath": "static/tabs/home_default.png","selectedIconPath": "static/tabs/home_selected.png"},{"text": "购物车","pagePath": "pages/cart/cart","iconPath": "static/tabs/cart_default.png","selectedIconPath": "static/tabs/cart_selected.png"},{"text": "我的","pagePath": "pages/my/my","iconPath": "static/tabs/user_default.png","selectedIconPath": "static/tabs/user_selected.png"}// {// 	"text": "SKU",// 	"pagePath": "pages/sku/sku"// }]},// 分包页面(需手动创建subPackages文件夹),按需加载"subPackages": [{// 子包的根目录"root": "pagesMember",// 页面路径和窗口表现,和上面 pages 一样// 访问的完整路径   如:/pagesMember/settings/settings"pages": [{"path": "settings/settings","style": {"navigationBarTitleText": "设置"}},{"path": "profile/profile","style": {"navigationBarTitleText": "个人信息",// 取消默认的导航栏"navigationStyle": "custom","navigationBarTextStyle": "white"}},{"path": "address/address","style": {"navigationBarTitleText": "地址管理"}},{"path": "address-form/address-form","style": {"navigationBarTitleText": "新建地址"}}]},{"root": "pagesOrder","pages": [{"path": "create/create","style": {"navigationBarTitleText": "结算"}},{"path": "detail/detail","style": {"navigationBarTitleText": "订单详情","navigationStyle": "custom"}},{"path": "payment/payment","style": {"navigationBarTitleText": "支付结果"}},{"path": "list/list","style": {"navigationBarTitleText": "订单列表"}}]}],// 预下载分包,分包预下载规则"preloadRule": {// 进入 我的 页面,预下载分包"pages/my/my": {"network": "all",// 分包 root的值"packages": ["pagesMember"]},"pages/cart/cart": {"network": "all","packages": ["pagesOrder"]}},"condition": { //模式配置,仅开发期间生效"current": 0, //当前激活的模式(list 的索引项)"list": [{"name": "", //模式名称"path": "", //启动页面,必选"query": "" //启动参数,在页面的onLoad函数里面得到}]}
}

2. 如果分包后主包还是超了可以把图片放在云服务上,把主包文件夹中一些大的js或者json等的文件移到子包中

3. 在hbuilderx中的运行 -> 运行到小程序模拟器 -> 运行时是否压缩代码,勾选

4. 微信小程序模拟器中的本地设置把压缩的都勾选


http://www.ppmy.cn/embedded/148886.html

相关文章

12寸半导体厂等保安全的设计思路

等级保护(等保)二级和三级的主要区别在于安全要求的严格程度、所需部署的安全措施和设备、以及对安全事件响应和处理的能力。以下是等保二级和三级之间的一些关键区别: 一、 安全要求严格程度: - 等保二级:适用于需要较高安全保护的信息系统,要求能够防范轻微的恶意攻击…

数组类算法 - 合集

************* C topics include&#xff1a; 数组类算法 - LeetBook - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台 283. 移动零 - 力扣&#xff08;LeetCode&#xff09; 27. 移除元素 - 力扣&#xff08;LeetCode&#xff09; 26. 删除有序数组中…

LLaMA-Factory(一)环境配置及包下载

LLaMA-Factory(一&#xff09;环境配置及包下载 本机配置1. git下载2.创建虚拟环境3. 下载官方包内依赖4. 下载bitsandbytes5. 启动项目6. 可能出现问题1&#xff1a;pip install 出现 error: subprocess-exited-with-error 错误7. 可能出现问题2&#xff1a; ModuleNotFoundEr…

记录jvm进程号

日常开发中&#xff0c;相信大家会经常用到这么一行命令&#xff1a; ps -ef | grep xxx.jar | grep -v grep | awk {print $2} | xargs -r kill -9 就是杀掉xxx相关的进程&#xff0c;然后启动&#xff0c;当然也还有其他的方式可以实现类似的功能&#xff0c;我就不列举了&…

重温设计模式--5、职责链模式

文章目录 职责链模式的详细介绍C 代码示例C示例代码2 职责链模式的详细介绍 定义与概念 职责链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;它旨在将请求的发送者和多个接收者解耦&#xff0c;让多个对象都有机会处理请求&am…

Leetcode 695 Max Area of Island

题意 给定一个二维矩阵&#xff0c;矩阵中包含0和1&#xff0c;所有相连的1被视为一个岛屿&#xff0c;求这些所有岛屿的最大区域是多少 题目链接 https://leetcode.com/problems/max-area-of-island/description/ 题解 遍历二维矩阵&#xff0c;当遇到没有被访问过的1时&…

【Linux进程】进程信号

目录 1. 信号 2. 信号的产生 2.1 终端按键 自定义信号处理 2.2 系统调用 kill raise abort 2.3 硬件异常 2.4 软件条件产生 思考 总结 1. 信号 在Linux中存在着一种通信的方式&#xff0c;与管道和System V IPC不同&#xff0c;更准确的说是一种通知机制&#xff0c;…

如何查看flink错误信息

flink出错时&#xff0c;可以通过以下步骤查看flink错误信息&#xff1a; 1.打开flink webui界面 2.进入overview或running jobs页面 3.点击出错的job name&#xff0c;出错的jobname一般后面的status会变红 4.在job 详情页面&#xff0c;点击exception&#xff0c;即可查看错…