Skip to content

性能优化

全面掌握小程序性能优化技巧,提升用户体验和应用性能。

⚡ 启动性能优化

代码包大小优化

javascript
// 1. 按需加载组件
// 避免在app.json中全局注册所有组件
// pages/index/index.json
{
  "usingComponents": {
    "custom-button": "/components/button/button",
    "user-card": "/components/user-card/user-card"
  }
}

// 2. 分包加载
// app.json
{
  "pages": [
    "pages/index/index",
    "pages/profile/profile"
  ],
  "subPackages": [
    {
      "root": "packageA",
      "name": "packageA",
      "pages": [
        "pages/cat/cat",
        "pages/dog/dog"
      ]
    },
    {
      "root": "packageB", 
      "name": "packageB",
      "pages": [
        "pages/apple/apple",
        "pages/banana/banana"
      ],
      "independent": true // 独立分包
    }
  ],
  "preloadRule": {
    "pages/index/index": {
      "network": "all",
      "packages": ["packageA"]
    }
  }
}

// 3. 代码压缩和混淆
// 使用微信开发者工具的代码压缩功能
// project.config.json
{
  "setting": {
    "es6": true,
    "postcss": true,
    "minified": true,
    "newFeature": true,
    "coverView": true,
    "autoAudits": false,
    "showShadowRootInWxmlPanel": true,
    "scopeDataCheck": false,
    "checkInvalidKey": true,
    "checkSiteMap": true,
    "uploadWithSourceMap": true,
    "babelSetting": {
      "ignore": [],
      "disablePlugins": [],
      "outputPath": ""
    }
  }
}

资源优化

javascript
// utils/imageOptimizer.js
class ImageOptimizer {
  constructor() {
    this.compressionQuality = 0.8
    this.maxWidth = 750
    this.maxHeight = 1334
  }

  // 压缩图片
  compressImage(src, options = {}) {
    return new Promise((resolve, reject) => {
      const {
        quality = this.compressionQuality,
        maxWidth = this.maxWidth,
        maxHeight = this.maxHeight
      } = options

      wx.compressImage({
        src: src,
        quality: quality * 100, // 微信API使用0-100
        success: (res) => {
          console.log('图片压缩成功', {
            original: src,
            compressed: res.tempFilePath
          })
          resolve(res.tempFilePath)
        },
        fail: (error) => {
          console.error('图片压缩失败', error)
          reject(error)
        }
      })
    })
  }

  // 获取图片信息
  getImageInfo(src) {
    return new Promise((resolve, reject) => {
      wx.getImageInfo({
        src: src,
        success: resolve,
        fail: reject
      })
    })
  }

  // 智能压缩(根据图片大小自动调整压缩参数)
  async smartCompress(src) {
    try {
      const imageInfo = await this.getImageInfo(src)
      const { width, height } = imageInfo
      
      // 根据图片尺寸调整压缩质量
      let quality = this.compressionQuality
      
      if (width > 1500 || height > 1500) {
        quality = 0.6 // 大图片使用更高压缩率
      } else if (width > 1000 || height > 1000) {
        quality = 0.7
      }
      
      return await this.compressImage(src, { quality })
    } catch (error) {
      console.error('智能压缩失败', error)
      return src // 压缩失败时返回原图
    }
  }

  // 批量压缩
  async batchCompress(srcList, options = {}) {
    const results = []
    
    for (const src of srcList) {
      try {
        const compressed = await this.compressImage(src, options)
        results.push({
          original: src,
          compressed: compressed,
          success: true
        })
      } catch (error) {
        results.push({
          original: src,
          compressed: src,
          success: false,
          error: error
        })
      }
    }
    
    return results
  }
}

module.exports = new ImageOptimizer()

预加载策略

javascript
// utils/preloader.js
class Preloader {
  constructor() {
    this.preloadedData = new Map()
    this.preloadedImages = new Set()
    this.preloadQueue = []
    this.isPreloading = false
  }

  // 预加载数据
  async preloadData(key, dataLoader, options = {}) {
    const {
      cache = true,
      priority = 'normal',
      timeout = 5000
    } = options

    if (this.preloadedData.has(key)) {
      return this.preloadedData.get(key)
    }

    try {
      console.log('预加载数据', key)
      
      const timeoutPromise = new Promise((_, reject) => {
        setTimeout(() => reject(new Error('预加载超时')), timeout)
      })
      
      const data = await Promise.race([
        dataLoader(),
        timeoutPromise
      ])
      
      if (cache) {
        this.preloadedData.set(key, data)
      }
      
      return data
    } catch (error) {
      console.error('预加载数据失败', key, error)
      return null
    }
  }

  // 预加载图片
  preloadImages(imageUrls) {
    return Promise.all(
      imageUrls.map(url => this.preloadImage(url))
    )
  }

  // 预加载单张图片
  preloadImage(url) {
    return new Promise((resolve) => {
      if (this.preloadedImages.has(url)) {
        resolve(true)
        return
      }

      wx.getImageInfo({
        src: url,
        success: () => {
          this.preloadedImages.add(url)
          console.log('图片预加载成功', url)
          resolve(true)
        },
        fail: (error) => {
          console.error('图片预加载失败', url, error)
          resolve(false)
        }
      })
    })
  }

  // 预加载页面数据
  async preloadPageData(pagePath, params = {}) {
    const cacheKey = `page_${pagePath}_${JSON.stringify(params)}`
    
    return this.preloadData(cacheKey, async () => {
      // 根据页面路径加载对应数据
      switch (pagePath) {
        case 'pages/home/home':
          return this.loadHomeData(params)
        case 'pages/profile/profile':
          return this.loadProfileData(params)
        case 'pages/article/article':
          return this.loadArticleData(params)
        default:
          return null
      }
    })
  }

  // 加载首页数据
  async loadHomeData(params) {
    const http = require('./http')
    
    const [banners, articles, categories] = await Promise.all([
      http.get('/banners'),
      http.get('/articles', { page: 1, limit: 10 }),
      http.get('/categories')
    ])
    
    return { banners, articles, categories }
  }

  // 加载个人资料数据
  async loadProfileData(params) {
    const http = require('./http')
    const { userId } = params
    
    const [userInfo, posts, followers] = await Promise.all([
      http.get(`/users/${userId}`),
      http.get(`/users/${userId}/posts`),
      http.get(`/users/${userId}/followers`)
    ])
    
    return { userInfo, posts, followers }
  }

  // 加载文章数据
  async loadArticleData(params) {
    const http = require('./http')
    const { articleId } = params
    
    const [article, comments, related] = await Promise.all([
      http.get(`/articles/${articleId}`),
      http.get(`/articles/${articleId}/comments`),
      http.get(`/articles/${articleId}/related`)
    ])
    
    return { article, comments, related }
  }

  // 获取预加载的数据
  getPreloadedData(key) {
    return this.preloadedData.get(key)
  }

  // 清理预加载数据
  clearPreloadedData(key = null) {
    if (key) {
      this.preloadedData.delete(key)
    } else {
      this.preloadedData.clear()
    }
  }

  // 预加载队列处理
  addToPreloadQueue(task) {
    this.preloadQueue.push(task)
    this.processPreloadQueue()
  }

  async processPreloadQueue() {
    if (this.isPreloading || this.preloadQueue.length === 0) {
      return
    }

    this.isPreloading = true

    while (this.preloadQueue.length > 0) {
      const task = this.preloadQueue.shift()
      
      try {
        await task()
      } catch (error) {
        console.error('预加载任务失败', error)
      }
    }

    this.isPreloading = false
  }
}

module.exports = new Preloader()

🎨 渲染性能优化

长列表优化

javascript
// components/virtual-list/virtual-list.js
Component({
  properties: {
    items: {
      type: Array,
      value: []
    },
    itemHeight: {
      type: Number,
      value: 100
    },
    containerHeight: {
      type: Number,
      value: 600
    },
    overscan: {
      type: Number,
      value: 5 // 预渲染的额外项目数
    }
  },

  data: {
    scrollTop: 0,
    visibleItems: [],
    startIndex: 0,
    endIndex: 0,
    totalHeight: 0,
    offsetY: 0
  },

  observers: {
    'items, itemHeight, containerHeight': function(items, itemHeight, containerHeight) {
      this.calculateVisibleItems()
    }
  },

  methods: {
    // 计算可见项目
    calculateVisibleItems() {
      const { items, itemHeight, containerHeight, overscan } = this.properties
      const { scrollTop } = this.data
      
      if (!items || items.length === 0) {
        this.setData({
          visibleItems: [],
          totalHeight: 0,
          offsetY: 0
        })
        return
      }

      const totalHeight = items.length * itemHeight
      const visibleCount = Math.ceil(containerHeight / itemHeight)
      
      const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan)
      const endIndex = Math.min(items.length - 1, startIndex + visibleCount + overscan * 2)
      
      const visibleItems = items.slice(startIndex, endIndex + 1).map((item, index) => ({
        ...item,
        _index: startIndex + index
      }))
      
      const offsetY = startIndex * itemHeight

      this.setData({
        visibleItems,
        startIndex,
        endIndex,
        totalHeight,
        offsetY
      })
    },

    // 滚动事件处理
    onScroll(e) {
      const scrollTop = e.detail.scrollTop
      
      // 节流处理
      if (this.scrollTimer) {
        clearTimeout(this.scrollTimer)
      }
      
      this.scrollTimer = setTimeout(() => {
        this.setData({ scrollTop }, () => {
          this.calculateVisibleItems()
        })
      }, 16) // 约60fps
    },

    // 项目点击事件
    onItemTap(e) {
      const { index } = e.currentTarget.dataset
      const item = this.data.visibleItems[index]
      
      this.triggerEvent('itemtap', {
        item: item,
        index: item._index
      })
    }
  }
})
xml
<!-- components/virtual-list/virtual-list.wxml -->
<scroll-view 
  class="virtual-list"
  scroll-y="{{true}}"
  style="height: {{containerHeight}}px"
  bindscroll="onScroll"
  scroll-top="{{scrollTop}}"
>
  <view class="virtual-list-container" style="height: {{totalHeight}}px">
    <view class="virtual-list-content" style="transform: translateY({{offsetY}}px)">
      <view 
        wx:for="{{visibleItems}}" 
        wx:key="_index"
        class="virtual-list-item"
        style="height: {{itemHeight}}px"
        data-index="{{index}}"
        bindtap="onItemTap"
      >
        <slot name="item" item="{{item}}" index="{{item._index}}"></slot>
      </view>
    </view>
  </view>
</scroll-view>

图片懒加载

javascript
// components/lazy-image/lazy-image.js
Component({
  properties: {
    src: {
      type: String,
      value: ''
    },
    placeholder: {
      type: String,
      value: '/images/placeholder.png'
    },
    threshold: {
      type: Number,
      value: 100 // 提前加载的距离
    },
    fadeIn: {
      type: Boolean,
      value: true
    }
  },

  data: {
    currentSrc: '',
    loaded: false,
    error: false,
    visible: false
  },

  lifetimes: {
    attached() {
      this.setData({
        currentSrc: this.properties.placeholder
      })
      this.createIntersectionObserver()
    },

    detached() {
      if (this.observer) {
        this.observer.disconnect()
      }
    }
  },

  methods: {
    // 创建交叉观察器
    createIntersectionObserver() {
      this.observer = this.createIntersectionObserver({
        rootMargin: `${this.properties.threshold}px`
      })

      this.observer.relativeToViewport().observe('.lazy-image', (res) => {
        if (res.intersectionRatio > 0 && !this.data.visible) {
          this.setData({ visible: true })
          this.loadImage()
        }
      })
    },

    // 加载图片
    loadImage() {
      const { src } = this.properties
      
      if (!src || this.data.loaded) {
        return
      }

      wx.getImageInfo({
        src: src,
        success: () => {
          this.setData({
            currentSrc: src,
            loaded: true,
            error: false
          })
          
          this.triggerEvent('load', { src })
        },
        fail: (error) => {
          console.error('图片加载失败', src, error)
          this.setData({
            error: true
          })
          
          this.triggerEvent('error', { src, error })
        }
      })
    },

    // 图片加载完成
    onImageLoad() {
      this.triggerEvent('imageload')
    },

    // 图片加载错误
    onImageError(e) {
      this.setData({
        error: true
      })
      this.triggerEvent('imageerror', e.detail)
    }
  }
})

动画性能优化

javascript
// utils/animationOptimizer.js
class AnimationOptimizer {
  constructor() {
    this.activeAnimations = new Map()
    this.animationFrame = null
  }

  // 创建高性能动画
  createAnimation(options = {}) {
    const {
      duration = 300,
      timingFunction = 'ease',
      delay = 0,
      transformOrigin = '50% 50% 0'
    } = options

    const animation = wx.createAnimation({
      duration,
      timingFunction,
      delay,
      transformOrigin
    })

    return animation
  }

  // 批量动画处理
  batchAnimations(animations) {
    return new Promise((resolve) => {
      let completedCount = 0
      const totalCount = animations.length

      animations.forEach((animationConfig, index) => {
        const { target, animation, callback } = animationConfig
        
        // 执行动画
        this.executeAnimation(target, animation).then(() => {
          completedCount++
          
          if (callback) {
            callback()
          }
          
          if (completedCount === totalCount) {
            resolve()
          }
        })
      })
    })
  }

  // 执行单个动画
  executeAnimation(target, animation) {
    return new Promise((resolve) => {
      const animationId = this.generateAnimationId()
      
      this.activeAnimations.set(animationId, {
        target,
        animation,
        startTime: Date.now()
      })

      // 应用动画
      target.setData({
        animationData: animation.export()
      })

      // 动画完成后清理
      setTimeout(() => {
        this.activeAnimations.delete(animationId)
        resolve()
      }, animation.duration || 300)
    })
  }

  // 使用requestAnimationFrame优化动画
  animateWithRAF(callback, duration = 300) {
    const startTime = Date.now()
    
    const animate = () => {
      const currentTime = Date.now()
      const elapsed = currentTime - startTime
      const progress = Math.min(elapsed / duration, 1)
      
      callback(progress)
      
      if (progress < 1) {
        this.animationFrame = requestAnimationFrame(animate)
      }
    }
    
    animate()
  }

  // 缓动函数
  easing: {
    linear: (t) => t,
    easeInQuad: (t) => t * t,
    easeOutQuad: (t) => t * (2 - t),
    easeInOutQuad: (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
    easeInCubic: (t) => t * t * t,
    easeOutCubic: (t) => (--t) * t * t + 1,
    easeInOutCubic: (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1
  },

  // 生成动画ID
  generateAnimationId() {
    return Date.now().toString(36) + Math.random().toString(36).substr(2)
  },

  // 停止所有动画
  stopAllAnimations() {
    this.activeAnimations.clear()
    
    if (this.animationFrame) {
      cancelAnimationFrame(this.animationFrame)
      this.animationFrame = null
    }
  },

  // 获取动画统计
  getAnimationStats() {
    return {
      activeCount: this.activeAnimations.size,
      animations: Array.from(this.activeAnimations.entries()).map(([id, config]) => ({
        id,
        duration: Date.now() - config.startTime
      }))
    }
  }
}

module.exports = new AnimationOptimizer()

💾 内存管理

内存监控

javascript
// utils/memoryMonitor.js
class MemoryMonitor {
  constructor() {
    this.memoryWarningCallbacks = []
    this.monitoringInterval = null
    this.memoryStats = {
      warnings: 0,
      lastWarningTime: null,
      peakUsage: 0
    }
    
    this.initMemoryWarningListener()
  }

  // 初始化内存警告监听
  initMemoryWarningListener() {
    wx.onMemoryWarning((res) => {
      console.warn('内存警告', res.level)
      
      this.memoryStats.warnings++
      this.memoryStats.lastWarningTime = Date.now()
      
      // 触发内存清理
      this.handleMemoryWarning(res.level)
      
      // 通知回调函数
      this.memoryWarningCallbacks.forEach(callback => {
        try {
          callback(res)
        } catch (error) {
          console.error('内存警告回调执行失败', error)
        }
      })
    })
  }

  // 处理内存警告
  handleMemoryWarning(level) {
    switch (level) {
      case 5: // 严重警告
        this.performAggressiveCleanup()
        break
      case 10: // 中等警告
        this.performModerateCleanup()
        break
      case 15: // 轻微警告
        this.performLightCleanup()
        break
    }
  }

  // 激进清理
  performAggressiveCleanup() {
    console.log('执行激进内存清理')
    
    // 清理所有缓存
    const cacheManager = require('./cacheManager')
    cacheManager.clear()
    
    // 清理图片缓存
    this.clearImageCache()
    
    // 清理预加载数据
    const preloader = require('./preloader')
    preloader.clearPreloadedData()
    
    // 强制垃圾回收(如果支持)
    if (wx.triggerGC) {
      wx.triggerGC()
    }
    
    wx.showToast({
      title: '已清理内存',
      icon: 'success'
    })
  }

  // 中等清理
  performModerateCleanup() {
    console.log('执行中等内存清理')
    
    // 清理过期缓存
    const cacheManager = require('./cacheManager')
    cacheManager.cleanExpired()
    
    // 清理部分预加载数据
    const preloader = require('./preloader')
    preloader.clearPreloadedData()
  }

  // 轻微清理
  performLightCleanup() {
    console.log('执行轻微内存清理')
    
    // 只清理过期数据
    const storage = require('./storage')
    storage.cleanExpired()
  }

  // 清理图片缓存
  clearImageCache() {
    // 这里可以实现图片缓存清理逻辑
    console.log('清理图片缓存')
  }

  // 添加内存警告回调
  onMemoryWarning(callback) {
    this.memoryWarningCallbacks.push(callback)
  }

  // 移除内存警告回调
  offMemoryWarning(callback) {
    const index = this.memoryWarningCallbacks.indexOf(callback)
    if (index > -1) {
      this.memoryWarningCallbacks.splice(index, 1)
    }
  }

  // 开始内存监控
  startMonitoring(interval = 30000) {
    if (this.monitoringInterval) {
      return
    }

    this.monitoringInterval = setInterval(() => {
      this.checkMemoryUsage()
    }, interval)
    
    console.log('开始内存监控')
  }

  // 停止内存监控
  stopMonitoring() {
    if (this.monitoringInterval) {
      clearInterval(this.monitoringInterval)
      this.monitoringInterval = null
      console.log('停止内存监控')
    }
  }

  // 检查内存使用情况
  checkMemoryUsage() {
    // 获取内存使用信息(如果API支持)
    if (wx.getMemoryInfo) {
      wx.getMemoryInfo({
        success: (res) => {
          console.log('内存使用情况', res)
          
          if (res.used > this.memoryStats.peakUsage) {
            this.memoryStats.peakUsage = res.used
          }
          
          // 如果内存使用率过高,主动清理
          const usageRate = res.used / res.total
          if (usageRate > 0.8) {
            this.performLightCleanup()
          }
        }
      })
    }
  }

  // 获取内存统计
  getMemoryStats() {
    return {
      ...this.memoryStats,
      isMonitoring: !!this.monitoringInterval
    }
  }

  // 重置统计
  resetStats() {
    this.memoryStats = {
      warnings: 0,
      lastWarningTime: null,
      peakUsage: 0
    }
  }
}

module.exports = new MemoryMonitor()

对象池管理

javascript
// utils/objectPool.js
class ObjectPool {
  constructor(createFn, resetFn, initialSize = 10) {
    this.createFn = createFn
    this.resetFn = resetFn
    this.pool = []
    this.inUse = new Set()
    
    // 预创建对象
    for (let i = 0; i < initialSize; i++) {
      this.pool.push(this.createFn())
    }
  }

  // 获取对象
  acquire() {
    let obj
    
    if (this.pool.length > 0) {
      obj = this.pool.pop()
    } else {
      obj = this.createFn()
    }
    
    this.inUse.add(obj)
    return obj
  }

  // 释放对象
  release(obj) {
    if (this.inUse.has(obj)) {
      this.inUse.delete(obj)
      
      // 重置对象状态
      if (this.resetFn) {
        this.resetFn(obj)
      }
      
      this.pool.push(obj)
    }
  }

  // 批量释放
  releaseAll() {
    this.inUse.forEach(obj => {
      if (this.resetFn) {
        this.resetFn(obj)
      }
      this.pool.push(obj)
    })
    
    this.inUse.clear()
  }

  // 清空池
  clear() {
    this.pool = []
    this.inUse.clear()
  }

  // 获取统计信息
  getStats() {
    return {
      poolSize: this.pool.length,
      inUseCount: this.inUse.size,
      totalCreated: this.pool.length + this.inUse.size
    }
  }
}

// 使用示例
const animationPool = new ObjectPool(
  // 创建函数
  () => wx.createAnimation({
    duration: 300,
    timingFunction: 'ease'
  }),
  // 重置函数
  (animation) => {
    // 重置动画状态
    animation.opacity(1).scale(1).rotate(0).translate(0, 0)
  },
  5 // 初始大小
)

module.exports = { ObjectPool, animationPool }

📊 性能监控

性能指标收集

javascript
// utils/performanceMonitor.js
class PerformanceMonitor {
  constructor() {
    this.metrics = {
      pageLoad: new Map(),
      apiRequest: new Map(),
      rendering: new Map(),
      memory: []
    }
    
    this.startTime = Date.now()
    this.initPerformanceObserver()
  }

  // 初始化性能观察器
  initPerformanceObserver() {
    // 监听页面性能
    const originalPage = Page
    Page = (options) => {
      const originalOnLoad = options.onLoad
      const originalOnShow = options.onShow
      const originalOnReady = options.onReady
      
      options.onLoad = function(query) {
        const startTime = Date.now()
        this._loadStartTime = startTime
        
        if (originalOnLoad) {
          originalOnLoad.call(this, query)
        }
      }
      
      options.onReady = function() {
        const endTime = Date.now()
        const loadTime = endTime - (this._loadStartTime || endTime)
        
        // 记录页面加载时间
        performanceMonitor.recordPageLoad(this.route, loadTime)
        
        if (originalOnReady) {
          originalOnReady.call(this)
        }
      }
      
      options.onShow = function() {
        this._showStartTime = Date.now()
        
        if (originalOnShow) {
          originalOnShow.call(this)
        }
      }
      
      return originalPage(options)
    }
  }

  // 记录页面加载时间
  recordPageLoad(route, loadTime) {
    if (!this.metrics.pageLoad.has(route)) {
      this.metrics.pageLoad.set(route, [])
    }
    
    this.metrics.pageLoad.get(route).push({
      loadTime,
      timestamp: Date.now()
    })
    
    console.log(`页面加载时间 ${route}: ${loadTime}ms`)
  }

  // 记录API请求时间
  recordApiRequest(url, responseTime, success = true) {
    if (!this.metrics.apiRequest.has(url)) {
      this.metrics.apiRequest.set(url, [])
    }
    
    this.metrics.apiRequest.get(url).push({
      responseTime,
      success,
      timestamp: Date.now()
    })
    
    console.log(`API请求时间 ${url}: ${responseTime}ms`)
  }

  // 记录渲染时间
  recordRenderTime(component, renderTime) {
    if (!this.metrics.rendering.has(component)) {
      this.metrics.rendering.set(component, [])
    }
    
    this.metrics.rendering.get(component).push({
      renderTime,
      timestamp: Date.now()
    })
    
    console.log(`渲染时间 ${component}: ${renderTime}ms`)
  }

  // 记录内存使用
  recordMemoryUsage(usage) {
    this.metrics.memory.push({
      usage,
      timestamp: Date.now()
    })
    
    // 只保留最近100条记录
    if (this.metrics.memory.length > 100) {
      this.metrics.memory.shift()
    }
  }

  // 获取性能报告
  getPerformanceReport() {
    const report = {
      summary: this.getSummary(),
      pageLoad: this.getPageLoadStats(),
      apiRequest: this.getApiRequestStats(),
      rendering: this.getRenderingStats(),
      memory: this.getMemoryStats(),
      generatedAt: new Date().toISOString()
    }
    
    return report
  }

  // 获取性能摘要
  getSummary() {
    const totalPages = this.metrics.pageLoad.size
    const totalApiRequests = Array.from(this.metrics.apiRequest.values())
      .reduce((sum, requests) => sum + requests.length, 0)
    
    return {
      uptime: Date.now() - this.startTime,
      totalPages,
      totalApiRequests,
      memoryRecords: this.metrics.memory.length
    }
  }

  // 获取页面加载统计
  getPageLoadStats() {
    const stats = {}
    
    this.metrics.pageLoad.forEach((records, route) => {
      const loadTimes = records.map(r => r.loadTime)
      stats[route] = {
        count: records.length,
        average: this.calculateAverage(loadTimes),
        min: Math.min(...loadTimes),
        max: Math.max(...loadTimes),
        recent: records.slice(-5) // 最近5次
      }
    })
    
    return stats
  }

  // 获取API请求统计
  getApiRequestStats() {
    const stats = {}
    
    this.metrics.apiRequest.forEach((records, url) => {
      const responseTimes = records.map(r => r.responseTime)
      const successCount = records.filter(r => r.success).length
      
      stats[url] = {
        count: records.length,
        successRate: (successCount / records.length * 100).toFixed(2) + '%',
        average: this.calculateAverage(responseTimes),
        min: Math.min(...responseTimes),
        max: Math.max(...responseTimes)
      }
    })
    
    return stats
  }

  // 获取渲染统计
  getRenderingStats() {
    const stats = {}
    
    this.metrics.rendering.forEach((records, component) => {
      const renderTimes = records.map(r => r.renderTime)
      stats[component] = {
        count: records.length,
        average: this.calculateAverage(renderTimes),
        min: Math.min(...renderTimes),
        max: Math.max(...renderTimes)
      }
    })
    
    return stats
  }

  // 获取内存统计
  getMemoryStats() {
    if (this.metrics.memory.length === 0) {
      return null
    }
    
    const usages = this.metrics.memory.map(m => m.usage)
    return {
      current: usages[usages.length - 1],
      average: this.calculateAverage(usages),
      peak: Math.max(...usages),
      trend: this.calculateTrend(usages)
    }
  }

  // 计算平均值
  calculateAverage(numbers) {
    if (numbers.length === 0) return 0
    return Math.round(numbers.reduce((sum, num) => sum + num, 0) / numbers.length)
  }

  // 计算趋势
  calculateTrend(numbers) {
    if (numbers.length < 2) return 'stable'
    
    const recent = numbers.slice(-10) // 最近10个数据点
    const first = recent[0]
    const last = recent[recent.length - 1]
    
    const change = (last - first) / first
    
    if (change > 0.1) return 'increasing'
    if (change < -0.1) return 'decreasing'
    return 'stable'
  }

  // 清理旧数据
  cleanup() {
    const cutoffTime = Date.now() - 24 * 60 * 60 * 1000 // 24小时前
    
    // 清理页面加载数据
    this.metrics.pageLoad.forEach((records, route) => {
      const filtered = records.filter(r => r.timestamp > cutoffTime)
      if (filtered.length === 0) {
        this.metrics.pageLoad.delete(route)
      } else {
        this.metrics.pageLoad.set(route, filtered)
      }
    })
    
    // 清理API请求数据
    this.metrics.apiRequest.forEach((records, url) => {
      const filtered = records.filter(r => r.timestamp > cutoffTime)
      if (filtered.length === 0) {
        this.metrics.apiRequest.delete(url)
      } else {
        this.metrics.apiRequest.set(url, filtered)
      }
    })
    
    // 清理渲染数据
    this.metrics.rendering.forEach((records, component) => {
      const filtered = records.filter(r => r.timestamp > cutoffTime)
      if (filtered.length === 0) {
        this.metrics.rendering.delete(component)
      } else {
        this.metrics.rendering.set(component, filtered)
      }
    })
    
    // 清理内存数据
    this.metrics.memory = this.metrics.memory.filter(m => m.timestamp > cutoffTime)
  }
}

const performanceMonitor = new PerformanceMonitor()
module.exports = performanceMonitor

性能测试工具

javascript
// utils/performanceTester.js
class PerformanceTester {
  constructor() {
    this.testResults = new Map()
  }

  // 测试函数执行时间
  async testFunction(name, fn, iterations = 1) {
    const results = []
    
    for (let i = 0; i < iterations; i++) {
      const startTime = Date.now()
      
      try {
        await fn()
        const endTime = Date.now()
        results.push(endTime - startTime)
      } catch (error) {
        console.error(`测试函数 ${name} 执行失败`, error)
        results.push(-1) // 表示失败
      }
    }
    
    const validResults = results.filter(r => r >= 0)
    const testResult = {
      name,
      iterations,
      results: validResults,
      average: validResults.length > 0 ? 
        validResults.reduce((sum, r) => sum + r, 0) / validResults.length : 0,
      min: validResults.length > 0 ? Math.min(...validResults) : 0,
      max: validResults.length > 0 ? Math.max(...validResults) : 0,
      successRate: (validResults.length / iterations * 100).toFixed(2) + '%'
    }
    
    this.testResults.set(name, testResult)
    console.log(`性能测试结果 ${name}:`, testResult)
    
    return testResult
  }

  // 测试页面渲染性能
  async testPageRender(pagePath, data = {}) {
    return this.testFunction(`page_render_${pagePath}`, async () => {
      // 模拟页面渲染
      const startTime = Date.now()
      
      // 这里可以添加具体的页面渲染测试逻辑
      await new Promise(resolve => setTimeout(resolve, 10))
      
      return Date.now() - startTime
    }, 10)
  }

  // 测试API请求性能
  async testApiRequest(url, options = {}) {
    const http = require('./http')
    
    return this.testFunction(`api_${url}`, async () => {
      await http.get(url, options.params, options)
    }, options.iterations || 5)
  }

  // 测试数据处理性能
  async testDataProcessing(name, data, processor) {
    return this.testFunction(`data_processing_${name}`, async () => {
      return processor(data)
    }, 10)
  }

  // 批量性能测试
  async runBatchTests(tests) {
    const results = []
    
    for (const test of tests) {
      try {
        const result = await this.testFunction(
          test.name,
          test.fn,
          test.iterations || 1
        )
        results.push(result)
      } catch (error) {
        console.error(`批量测试失败 ${test.name}`, error)
        results.push({
          name: test.name,
          error: error.message
        })
      }
    }
    
    return results
  }

  // 生成性能测试报告
  generateReport() {
    const report = {
      testCount: this.testResults.size,
      tests: Array.from(this.testResults.values()),
      summary: this.generateSummary(),
      generatedAt: new Date().toISOString()
    }
    
    return report
  }

  // 生成测试摘要
  generateSummary() {
    const tests = Array.from(this.testResults.values())
    
    if (tests.length === 0) {
      return { message: '暂无测试数据' }
    }
    
    const averages = tests.map(t => t.average).filter(a => a > 0)
    
    return {
      totalTests: tests.length,
      averageTime: averages.length > 0 ? 
        (averages.reduce((sum, a) => sum + a, 0) / averages.length).toFixed(2) : 0,
      fastestTest: tests.reduce((fastest, test) => 
        test.average > 0 && (fastest.average === 0 || test.average < fastest.average) ? test : fastest
      ),
      slowestTest: tests.reduce((slowest, test) => 
        test.average > slowest.average ? test : slowest
      )
    }
  }

  // 清理测试结果
  clearResults() {
    this.testResults.clear()
  }
}

module.exports = new PerformanceTester()

🔧 性能优化工具

代码分析工具

javascript
// utils/codeAnalyzer.js
class CodeAnalyzer {
  constructor() {
    this.analysisResults = {
      unusedFiles: [],
      largeFunctions: [],
      duplicateCode: [],
      performanceIssues: []
    }
  }

  // 分析代码性能问题
  analyzePerformanceIssues(code, filePath) {
    const issues = []
    
    // 检查同步存储使用
    if (code.includes('getStorageSync') || code.includes('setStorageSync')) {
      issues.push({
        type: 'sync_storage',
        message: '使用同步存储可能阻塞主线程',
        file: filePath,
        suggestion: '考虑使用异步存储API'
      })
    }
    
    // 检查大量DOM操作
    const setDataMatches = code.match(/setData\s*\(/g)
    if (setDataMatches && setDataMatches.length > 10) {
      issues.push({
        type: 'frequent_setdata',
        message: '频繁调用setData可能影响性能',
        file: filePath,
        count: setDataMatches.length,
        suggestion: '合并setData调用或使用批量更新'
      })
    }
    
    // 检查未优化的循环
    if (code.includes('for') && code.includes('setData')) {
      issues.push({
        type: 'loop_setdata',
        message: '循环中调用setData会严重影响性能',
        file: filePath,
        suggestion: '将数据收集后一次性setData'
      })
    }
    
    // 检查内存泄漏风险
    if (code.includes('setInterval') && !code.includes('clearInterval')) {
      issues.push({
        type: 'memory_leak',
        message: '可能存在定时器内存泄漏',
        file: filePath,
        suggestion: '确保在页面卸载时清理定时器'
      })
    }
    
    this.analysisResults.performanceIssues.push(...issues)
    return issues
  }

  // 分析函数复杂度
  analyzeFunctionComplexity(code, filePath) {
    const functions = []
    const functionRegex = /function\s+(\w+)\s*\([^)]*\)\s*{([^}]*)}/g
    let match
    
    while ((match = functionRegex.exec(code)) !== null) {
      const [, name, body] = match
      const complexity = this.calculateComplexity(body)
      
      if (complexity > 10) {
        functions.push({
          name,
          complexity,
          file: filePath,
          suggestion: '函数过于复杂,建议拆分'
        })
      }
    }
    
    this.analysisResults.largeFunctions.push(...functions)
    return functions
  }

  // 计算圈复杂度
  calculateComplexity(code) {
    let complexity = 1 // 基础复杂度
    
    // 条件语句
    complexity += (code.match(/if\s*\(/g) || []).length
    complexity += (code.match(/else\s+if/g) || []).length
    complexity += (code.match(/switch\s*\(/g) || []).length
    complexity += (code.match(/case\s+/g) || []).length
    
    // 循环语句
    complexity += (code.match(/for\s*\(/g) || []).length
    complexity += (code.match(/while\s*\(/g) || []).length
    complexity += (code.match(/do\s*{/g) || []).length
    
    // 逻辑操作符
    complexity += (code.match(/&&/g) || []).length
    complexity += (code.match(/\|\|/g) || []).length
    
    return complexity
  }

  // 检测重复代码
  detectDuplicateCode(files) {
    const codeBlocks = new Map()
    const duplicates = []
    
    files.forEach(({ content, path }) => {
      // 简单的重复代码检测(基于行)
      const lines = content.split('\n')
      
      for (let i = 0; i < lines.length - 5; i++) {
        const block = lines.slice(i, i + 5).join('\n').trim()
        
        if (block.length > 50) { // 忽略太短的代码块
          if (codeBlocks.has(block)) {
            duplicates.push({
              block,
              files: [codeBlocks.get(block), path],
              lines: [codeBlocks.get(block).startLine, i + 1]
            })
          } else {
            codeBlocks.set(block, { path, startLine: i + 1 })
          }
        }
      }
    })
    
    this.analysisResults.duplicateCode = duplicates
    return duplicates
  }

  // 生成分析报告
  generateAnalysisReport() {
    return {
      summary: {
        performanceIssues: this.analysisResults.performanceIssues.length,
        largeFunctions: this.analysisResults.largeFunctions.length,
        duplicateCode: this.analysisResults.duplicateCode.length
      },
      details: this.analysisResults,
      recommendations: this.generateRecommendations(),
      generatedAt: new Date().toISOString()
    }
  }

  // 生成优化建议
  generateRecommendations() {
    const recommendations = []
    
    if (this.analysisResults.performanceIssues.length > 0) {
      recommendations.push({
        priority: 'high',
        category: 'performance',
        title: '修复性能问题',
        description: `发现 ${this.analysisResults.performanceIssues.length} 个性能问题,建议优先处理`
      })
    }
    
    if (this.analysisResults.largeFunctions.length > 0) {
      recommendations.push({
        priority: 'medium',
        category: 'maintainability',
        title: '重构复杂函数',
        description: `发现 ${this.analysisResults.largeFunctions.length} 个复杂函数,建议拆分`
      })
    }
    
    if (this.analysisResults.duplicateCode.length > 0) {
      recommendations.push({
        priority: 'medium',
        category: 'maintainability',
        title: '消除重复代码',
        description: `发现 ${this.analysisResults.duplicateCode.length} 处重复代码,建议提取公共函数`
      })
    }
    
    return recommendations
  }

  // 清理分析结果
  clearResults() {
    this.analysisResults = {
      unusedFiles: [],
      largeFunctions: [],
      duplicateCode: [],
      performanceIssues: []
    }
  }
}

module.exports = new CodeAnalyzer()

📈 性能优化最佳实践

通用优化策略

javascript
// utils/optimizationStrategies.js
class OptimizationStrategies {
  constructor() {
    this.strategies = new Map()
    this.initStrategies()
  }

  // 初始化优化策略
  initStrategies() {
    // 数据更新优化
    this.strategies.set('data_update', {
      name: '数据更新优化',
      description: '优化setData调用,减少不必要的渲染',
      implement: this.optimizeDataUpdate.bind(this)
    })

    // 图片加载优化
    this.strategies.set('image_loading', {
      name: '图片加载优化',
      description: '实现图片懒加载和压缩',
      implement: this.optimizeImageLoading.bind(this)
    })

    // 网络请求优化
    this.strategies.set('network_request', {
      name: '网络请求优化',
      description: '实现请求缓存和批量处理',
      implement: this.optimizeNetworkRequest.bind(this)
    })

    // 内存管理优化
    this.strategies.set('memory_management', {
      name: '内存管理优化',
      description: '实现内存监控和自动清理',
      implement: this.optimizeMemoryManagement.bind(this)
    })
  }

  // 数据更新优化实现
  optimizeDataUpdate(page) {
    const originalSetData = page.setData
    let pendingData = {}
    let updateTimer = null

    page.setData = function(data, callback) {
      // 合并待更新的数据
      Object.assign(pendingData, data)

      // 清除之前的定时器
      if (updateTimer) {
        clearTimeout(updateTimer)
      }

      // 延迟更新,合并多次setData调用
      updateTimer = setTimeout(() => {
        originalSetData.call(this, pendingData, callback)
        pendingData = {}
        updateTimer = null
      }, 16) // 约60fps
    }

    console.log('已应用数据更新优化')
  }

  // 图片加载优化实现
  optimizeImageLoading(options = {}) {
    const {
      lazyLoad = true,
      compression = true,
      placeholder = '/images/placeholder.png'
    } = options

    // 创建图片加载管理器
    const imageManager = {
      loadedImages: new Set(),
      loadingImages: new Map(),

      loadImage(src, callback) {
        if (this.loadedImages.has(src)) {
          callback(null, src)
          return
        }

        if (this.loadingImages.has(src)) {
          this.loadingImages.get(src).push(callback)
          return
        }

        this.loadingImages.set(src, [callback])

        wx.getImageInfo({
          src: src,
          success: (res) => {
            this.loadedImages.add(src)
            const callbacks = this.loadingImages.get(src) || []
            callbacks.forEach(cb => cb(null, res.path))
            this.loadingImages.delete(src)
          },
          fail: (error) => {
            const callbacks = this.loadingImages.get(src) || []
            callbacks.forEach(cb => cb(error))
            this.loadingImages.delete(src)
          }
        })
      }
    }

    console.log('已应用图片加载优化')
    return imageManager
  }

  // 网络请求优化实现
  optimizeNetworkRequest(options = {}) {
    const {
      cacheEnabled = true,
      batchEnabled = true,
      retryEnabled = true
    } = options

    const requestManager = {
      cache: new Map(),
      batchQueue: [],
      batchTimer: null,

      request(config) {
        // 缓存检查
        if (cacheEnabled && config.method === 'GET') {
          const cacheKey = this.getCacheKey(config)
          const cached = this.cache.get(cacheKey)
          
          if (cached && Date.now() - cached.timestamp < 300000) { // 5分钟缓存
            return Promise.resolve(cached.data)
          }
        }

        // 批量处理
        if (batchEnabled && config.batch) {
          return this.addToBatch(config)
        }

        // 执行请求
        return this.executeRequest(config)
      },

      getCacheKey(config) {
        return `${config.method}:${config.url}:${JSON.stringify(config.data || {})}`
      },

      executeRequest(config) {
        return new Promise((resolve, reject) => {
          wx.request({
            ...config,
            success: (res) => {
              // 缓存响应
              if (cacheEnabled && config.method === 'GET') {
                const cacheKey = this.getCacheKey(config)
                this.cache.set(cacheKey, {
                  data: res.data,
                  timestamp: Date.now()
                })
              }
              
              resolve(res.data)
            },
            fail: reject
          })
        })
      },

      addToBatch(config) {
        return new Promise((resolve, reject) => {
          this.batchQueue.push({ config, resolve, reject })

          if (this.batchTimer) {
            clearTimeout(this.batchTimer)
          }

          this.batchTimer = setTimeout(() => {
            this.processBatch()
          }, 100) // 100ms内的请求合并处理
        })
      },

      processBatch() {
        const batch = this.batchQueue.splice(0)
        
        // 这里可以实现具体的批量请求逻辑
        batch.forEach(({ config, resolve, reject }) => {
          this.executeRequest(config).then(resolve).catch(reject)
        })
      }
    }

    console.log('已应用网络请求优化')
    return requestManager
  }

  // 内存管理优化实现
  optimizeMemoryManagement(options = {}) {
    const {
      autoCleanup = true,
      warningThreshold = 0.8,
      cleanupInterval = 60000 // 1分钟
    } = options

    const memoryManager = {
      cleanupTimer: null,
      caches: [],

      init() {
        if (autoCleanup) {
          this.startAutoCleanup()
        }

        // 监听内存警告
        wx.onMemoryWarning((res) => {
          console.warn('内存警告,开始清理', res.level)
          this.performCleanup(res.level)
        })
      },

      startAutoCleanup() {
        this.cleanupTimer = setInterval(() => {
          this.performRoutineCleanup()
        }, cleanupInterval)
      },

      stopAutoCleanup() {
        if (this.cleanupTimer) {
          clearInterval(this.cleanupTimer)
          this.cleanupTimer = null
        }
      },

      registerCache(cache) {
        this.caches.push(cache)
      },

      performCleanup(level = 10) {
        // 根据警告级别执行不同程度的清理
        this.caches.forEach(cache => {
          if (cache.clear) {
            cache.clear()
          }
        })

        // 触发垃圾回收
        if (wx.triggerGC) {
          wx.triggerGC()
        }
      },

      performRoutineCleanup() {
        // 定期清理过期数据
        this.caches.forEach(cache => {
          if (cache.cleanExpired) {
            cache.cleanExpired()
          }
        })
      }
    }

    memoryManager.init()
    console.log('已应用内存管理优化')
    return memoryManager
  }

  // 应用优化策略
  applyStrategy(strategyName, target, options = {}) {
    const strategy = this.strategies.get(strategyName)
    
    if (!strategy) {
      console.error(`未找到优化策略: ${strategyName}`)
      return false
    }

    try {
      const result = strategy.implement(target, options)
      console.log(`已应用优化策略: ${strategy.name}`)
      return result
    } catch (error) {
      console.error(`应用优化策略失败: ${strategy.name}`, error)
      return false
    }
  }

  // 批量应用优化策略
  applyMultipleStrategies(strategies, target, options = {}) {
    const results = {}
    
    strategies.forEach(strategyName => {
      results[strategyName] = this.applyStrategy(strategyName, target, options)
    })
    
    return results
  }

  // 获取所有可用策略
  getAvailableStrategies() {
    return Array.from(this.strategies.entries()).map(([key, strategy]) => ({
      key,
      name: strategy.name,
      description: strategy.description
    }))
  }
}

module.exports = new OptimizationStrategies()

📚 相关文档


通过系统的性能优化,打造流畅高效的小程序用户体验!🚀

连接多端,赋能创新