微信小程序性能优化

发布于:2025-08-09 ⋅ 阅读:(12) ⋅ 点赞:(0)

一、setData 优化(减少通信开销)

问题:频繁调用 setData 或传递大量数据会导致性能卡顿

优化前(错误示例):

// 循环中多次调用 setData,性能差
for (let i = 0; i < 100; i++) {
  this.setData({
    [`list[${i}]`]: { id: i, name: `item${i}` }
  });
}

// 传递无关数据(整个对象)
this.setData({
  user: { name: '张三', age: 20, address: '...' } // 实际只修改了 name
});

优化后(正确示例):

// 1. 合并修改,减少调用次数
const newList = [];
for (let i = 0; i < 100; i++) {
  newList.push({ id: i, name: `item${i}` });
}
this.setData({ list: newList }); // 一次调用完成

// 2. 只传递变化的字段
this.setData({
  'user.name': '张三' // 仅更新修改的字段
});

// 3. 避免在 data 中存储无需渲染的数据
// 用 this 直接存储非渲染数据(不参与页面渲染)
this.tempData = { log: '临时日志', timer: 123 }; // 不会触发渲染

二、分包加载(解决包体积过大)

问题:主包体积超过 2MB 导致无法发布

优化方案: 在 app.json 中配置分包,将非核心页面拆分到分包

{
  "pages": [
    "pages/index/index", // 主包页面(首页必须在主包)
    "pages/login/login"
  ],
  "subpackages": [
    {
      "root": "packageA", // 分包A
      "pages": [
        "pages/detail/detail", // 路径:packageA/pages/detail/detail
        "pages/setting/setting"
      ]
    },
    {
      "root": "packageB", // 分包B
      "pages": ["pages/help/help"]
    }
  ],
  "preloadRule": {
    // 进入首页后,预加载 packageA(提升用户访问分包页面的速度)
    "pages/index/index": {
      "network": "all", // 所有网络环境都预加载
      "packages": ["packageA"]
    }
  }
}

三、虚拟列表(优化长列表渲染)

问题:列表数据量过大(如 1000 条)导致渲染卡顿

优化方案: 使用 recycle-view 只渲染可视区域内的列表项

<!-- pages/list/list.wxml -->
<view class="list-container">
  <recycle-view 
    class="recycle-list"
    height="600rpx" <!-- 固定高度,用于计算可视区域 -->
    width="100%"
    buffer-size="5" <!-- 上下预加载5个项 -->
    data-key="id" <!-- 数据唯一标识字段 -->
    bind:itemtap="onItemTap"
  >
    <!-- 列表项模板 -->
    <view slot="item" class="list-item">
      <text>{{ item.name }}</text>
    </view>
  </recycle-view>
</view>
// pages/list/list.js
Page({
  onLoad() {
    // 1. 初始化虚拟列表
    this.recycleList = this.selectComponent('.recycle-list');
    
    // 2. 模拟1000条数据
    const bigData = [];
    for (let i = 0; i < 1000; i++) {
      bigData.push({ id: i, name: `项目 ${i + 1}` });
    }
    
    // 3. 加载数据到虚拟列表(仅渲染可视区域)
    this.recycleList.setData({
      list: bigData
    });
  }
});

四、启动优化(减少白屏时间)

问题:首次启动时初始化逻辑过多导致白屏

优化方案: 延迟加载非必要数据 + 骨架屏

<!-- pages/index/index.wxml(骨架屏示例) -->
<view class="container">
  <!-- 骨架屏(页面加载完成前显示) -->
  <view wx:if="{{!isLoaded}}" class="skeleton">
    <view class="skeleton-title"></view>
    <view class="skeleton-list">
      <view class="skeleton-item"></view>
      <view class="skeleton-item"></view>
    </view>
  </view>
  
  <!-- 实际内容(加载完成后显示) -->
  <view wx:else>
    <text>{{ title }}</text>
    <view wx:for="{{ list }}">{{ item.name }}</view>
  </view>
</view>
// app.js
App({
  onLaunch() {
    // 1. 优先加载核心数据(如用户登录状态)
    this.checkLoginStatus();
    
    // 2. 延迟加载非核心数据(利用 setTimeout 放到下一帧)
    setTimeout(() => {
      this.loadRecommendData(); // 推荐内容可延后加载
      this.initAnalytics(); // 统计分析可延后初始化
    }, 0);
  },
  
  checkLoginStatus() {
    // 核心逻辑:检查登录状态
    wx.getStorage({
      key: 'token',
      success: (res) => { /* 已登录逻辑 */ },
      fail: () => { /* 未登录逻辑 */ }
    });
  }
});

五、缓存策略(减少重复请求)

问题:频繁请求相同数据导致网络开销大

优化方案: 缓存接口数据,设置过期时间

// utils/request.js(封装带缓存的请求工具)
function requestWithCache(url, options = {}) {
  const { cacheTime = 300000 } = options; // 默认缓存5分钟
  const cacheKey = `cache_${url}`;
  
  // 1. 先查缓存
  return new Promise((resolve) => {
    wx.getStorage({
      key: cacheKey,
      success: (res) => {
        const { data, timestamp } = res.data;
        // 缓存未过期,直接返回缓存数据
        if (Date.now() - timestamp < cacheTime) {
          return resolve(data);
        }
      },
      complete: () => {
        // 2. 缓存过期或无缓存,发起请求
        wx.request({
          url,
          ...options,
          success: (res) => {
            // 3. 缓存请求结果
            wx.setStorage({
              key: cacheKey,
              data: { data: res.data, timestamp: Date.now() }
            });
            resolve(res.data);
          }
        });
      }
    });
  });
}

// 使用示例
requestWithCache('https://api.example.com/list', { cacheTime: 600000 })
  .then(data => {
    console.log('数据:', data);
  });

六、动画优化(避免卡顿)

问题:用 setData 驱动高频动画导致掉帧

优化方案: 使用 wx.createAnimation 或 CSS 动画

// 优化前(用 setData 驱动动画,性能差)
let left = 0;
setInterval(() => {
  left += 10;
  this.setData({ ballLeft: left }); // 高频调用 setData
}, 16);

// 优化后(用 createAnimation,在渲染层执行动画)
const animation = wx.createAnimation({
  duration: 1000,
  timingFunction: 'linear'
});

// 循环动画
setInterval(() => {
  animation.translateX(300).step();
  animation.translateX(0).step({ duration: 0 }); // 复位(无动画)
  this.setData({ animationData: animation.export() });
}, 1000);

总结

小程序性能优化的核心思路是:

  1. 减少 setData 通信成本(合并调用、精简数据);
  2. 控制渲染节点数量(虚拟列表、简化 DOM 结构);
  3. 合理利用缓存和分包(减少网络请求和包体积);
  4. 避免主线程阻塞(延迟非必要任务、优化动画)。

以上代码可直接在小程序中使用,根据实际业务场景调整参数即可。


网站公告

今日签到

点亮在社区的每一天
去签到