杭州建网站企业,装饰公司响应式网站建设案例,做单页网站需要做什么,推广软文怎么写性能优化是任何应用开发中的重要组成部分#xff0c;尤其是在移动环境中。对于微信小程序而言#xff0c;随着用户量的增加和应用功能的丰富#xff0c;性能优化显得尤为关键。良好的性能不仅提升用户体验#xff0c;还能增加用户留存率和应用的使用频率。我们将探讨如何在…性能优化是任何应用开发中的重要组成部分尤其是在移动环境中。对于微信小程序而言随着用户量的增加和应用功能的丰富性能优化显得尤为关键。良好的性能不仅提升用户体验还能增加用户留存率和应用的使用频率。我们将探讨如何在微信小程序中进行性能优化涵盖从首屏加载、分包、网络请求到渲染性能等多个方面。
网络请求合并请求减少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 modewidthFix data-src{{item.image}} bindloadimageLoad/// 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/indexpath: 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/settingspages: [{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. 微信小程序模拟器中的本地设置把压缩的都勾选 七、分包异步化
分包异步化原理
原有的分包隔离机制导致各分包之间无法引用自定义组件或逻辑代码分包异步化能力打通了不同分包的引用关系支持跨分包组件和跨分包方法。
背景与案例
我们一般使用小程序插件的时候喜欢将其放在分包中因为插件体积会打包进主包内很容易造成主包体积超过 2M 从而无法发布我们暂且叫这个有插件的分包叫分包P这时候另外两个业务分包XY想引入这个分包P里的插件插件里包含了几个组件和一些接口函数。
方案一因为分包里本身就是可以引入插件的所以想直接在分包XY里面分别引入插件但是同一个插件是不能在一个项目里多次引用的所以这个方案不行 方案二把插件放在主包里这样虽然可以实现但是插件大小会打包进主包容易超过 2M 无法发布方案三分包异步化将插件/逻辑代码抽成一个模块单独放在一个分包P下分包XY通过分包异步化来引入。
subpackages: [{root: pagesPlugin1,pages: [page-index/index],plugins: {assist-photo: {version: 3.2.1,provider: wxcf13b931313209a4}}},{root: pagesPlugin2,pages: [page-index/index]}
]这是分包2的代码
style langless
/styletemplatediv这是pagesPlugin2/divchose-part/chose-part
/templatescript
import wepy from wepy/core
wepy.page({data: {},onShow() {}
})
/script
config
{usingComponents: {chose-part: ../../pagesPlugin1/components/chose-part/index,},componentPlaceholder: {chose-part: view}
}
/config
这个时候打开分包2的页面就可以看到这个组件了
跨分包 JS 代码引用
分包2想调用分包1的接口这里在分包1先导出一些函数pagesPlugin1/utils/index.js
export const sayHello () {console.log(hello)
}pagesPlugin2/page-index/index 在分包2调用
import wepy from wepy/core
wepy.page({data: {},methods: {getPagesPlugin1 () {require.async(../../pagesPlugin1/utils/index.js).then(pkg {console.log(utils, pkg)pkg.sayHello()}).catch(({mod, errMsg}) {console.error(path: ${mod}, ${errMsg})})}},onShow() {this.getPagesPlugin1()}
})注意如果是使用 wepy 这样的框架则需要在分包的页面中引入一下这些接口函数否则最终打包不会打包这个接口函数因为识别不出这些依赖 跨分包方法
在小程序开发过程中可以通过require回调函数或requireAsync异步调用两种方法引用其他分包的逻辑代码。具体操作如下
// 使用回调函数风格的调用
require(../subPackageB/utils.js, utils {console.log(utils.whoami) // Wechat MiniProgram
}, ({mod, errMsg}) {console.error(path: ${mod}, ${errMsg})
})
// 或者使用 Promise 风格的调用
require.async(../commonPackage/index.js).then(pkg {pkg.getPackageName() // common
}).catch(({mod, errMsg}) {console.error(path: ${mod}, ${errMsg})
})在其它分包中的插件也可以通过类似的方法调用
// 使用回调函数风格的调用
requirePlugin(live-player-plugin, livePlayer {console.log(livePlayer.getPluginVersion())
}, ({mod, errMsg}) {console.error(path: ${mod}, ${errMsg})
})
// 或者使用 Promise 风格的调用
requirePlugin.async(live-player-plugin).then(livePlayer {console.log(livePlayer.getPluginVersion())
}).catch(({mod, errMsg}) {console.error(path: ${mod}, ${errMsg})
})