智能预加载:基于用户行为和路由预测

核心概念

智能预加载通过分析用户行为模式、路由关系和页面重要性,在用户实际访问前预先加载资源,显著提升用户体验。

实现架构

1. 行为数据收集层

class UserBehaviorTracker {
  constructor() {
    this.sessionData = {
      clickPaths: [],
      hoverDurations: new Map(),
      scrollDepth: new Map(),
      visitFrequency: new Map(),
      sessionStart: Date.now()
    }
    this.setupTracking()
  }

  setupTracking() {
    // 链接悬停跟踪
    this.trackLinkHovers()
    // 点击流分析
    this.trackClicks()
    // 滚动深度监控
    this.trackScrollBehavior()
    // 页面停留时间
    this.trackPageStayTime()
  }

  trackLinkHovers() {
    document.addEventListener('mouseover', (e) => {
      const link = e.target.closest('a[href]')
      if (link && this.isInternalLink(link.href)) {
        const hoverStart = Date.now()
        const routePath = this.extractRoutePath(link.href)
        
        link.addEventListener('mouseleave', () => {
          const duration = Date.now() - hoverStart
          this.recordHoverDuration(routePath, duration)
        }, { once: true })
      }
    })
  }

  trackClicks() {
    document.addEventListener('click', (e) => {
      const link = e.target.closest('a[href]')
      if (link && this.isInternalLink(link.href)) {
        const routePath = this.extractRoutePath(link.href)
        this.recordClickPath(routePath)
      }
    })
  }

  recordHoverDuration(routePath, duration) {
    const current = this.sessionData.hoverDurations.get(routePath) || []
    current.push(duration)
    this.sessionData.hoverDurations.set(routePath, current.slice(-10)) // 保留最近10次
  }

  recordClickPath(routePath) {
    this.sessionData.clickPaths.push({
      path: routePath,
      timestamp: Date.now()
    })
  }
}

2. 预测引擎

class RoutePredictor {
  constructor(behaviorTracker) {
    this.tracker = behaviorTracker
    this.routeGraph = new Map() // 路由关系图
    this.predictionWeights = {
      hoverDuration: 0.3,
      clickFrequency: 0.4,
      routeProximity: 0.2,
      timeContext: 0.1
    }
  }

  // 构建路由关系图
  buildRouteGraph(routes) {
    routes.forEach(route => {
      this.routeGraph.set(route.path, {
        ...route,
        connections: new Map(),
        importance: this.calculateRouteImportance(route)
      })
    })
  }

  // 预测下一个可能访问的路由
  predictNextRoutes(currentRoute, limit = 3) {
    const predictions = new Map()

    // 基于点击流分析
    const clickBased = this.predictFromClickPatterns(currentRoute)
    // 基于悬停行为
    const hoverBased = this.predictFromHoverBehavior(currentRoute)
    // 基于路由关系
    const routeBased = this.predictFromRouteRelations(currentRoute)
    // 基于时间上下文
    const timeBased = this.predictFromTimeContext(currentRoute)

    // 合并预测结果
    this.mergePredictions(predictions, clickBased, this.predictionWeights.clickFrequency)
    this.mergePredictions(predictions, hoverBased, this.predictionWeights.hoverDuration)
    this.mergePredictions(predictions, routeBased, this.predictionWeights.routeProximity)
    this.mergePredictions(predictions, timeBased, this.predictionWeights.timeContext)

    // 排序并返回Top N
    return Array.from(predictions.entries())
      .sort(([, a], [, b]) => b - a)
      .slice(0, limit)
      .map(([route]) => route)
  }

  predictFromHoverBehavior(currentRoute) {
    const predictions = new Map()
    const hoverData = this.tracker.sessionData.hoverDurations

    for (const [route, durations] of hoverData) {
      if (route !== currentRoute) {
        const avgDuration = durations.reduce((a, b) => a + b, 0) / durations.length
        const score = this.normalizeHoverScore(avgDuration)
        predictions.set(route, score)
      }
    }

    return predictions
  }

  predictFromClickPatterns(currentRoute) {
    const predictions = new Map()
    const clickPaths = this.tracker.sessionData.clickPaths
    const recentClicks = clickPaths.filter(click => 
      Date.now() - click.timestamp < 30 * 60 * 1000 // 30分钟内
    )

    // 分析点击序列模式
    const transitionCounts = new Map()
    for (let i = 0; i < recentClicks.length - 1; i++) {
      const from = recentClicks[i].path
      const to = recentClicks[i + 1].path
      const key = `${from}->${to}`
      transitionCounts.set(key, (transitionCounts.get(key) || 0) + 1)
    }

    // 计算从当前路由出发的概率
    for (const [transition, count] of transitionCounts) {
      const [from, to] = transition.split('->')
      if (from === currentRoute && to !== currentRoute) {
        predictions.set(to, count / recentClicks.length)
      }
    }

    return predictions
  }

  normalizeHoverScore(duration) {
    // 悬停时间越长,点击可能性越大
    return Math.min(duration / 1000, 1) // 归一化到0-1
  }
}

3. 预加载控制器

class SmartPreloader {
  constructor(predictor, router) {
    this.predictor = predictor
    this.router = router
    this.preloadQueue = new Set()
    this.maxConcurrent = 2
    this.currentPreloads = 0
    
    this.setupPreloadTriggers()
  }

  setupPreloadTriggers() {
    // 路由变化时预测
    this.router.afterEach((to, from) => {
      this.schedulePreload(to.path)
    })

    // 用户空闲时预加载
    this.setupIdlePreloading()
    
    // 网络空闲时预加载
    this.setupNetworkAwarePreloading()
  }

  async schedulePreload(currentRoute) {
    const predictedRoutes = this.predictor.predictNextRoutes(currentRoute)
    
    for (const route of predictedRoutes) {
      if (!this.preloadQueue.has(route) && this.shouldPreload(route)) {
        this.preloadQueue.add(route)
      }
    }

    await this.processPreloadQueue()
  }

  async processPreloadQueue() {
    while (this.preloadQueue.size > 0 && this.currentPreloads < this.maxConcurrent) {
      const route = this.preloadQueue.values().next().value
      this.preloadQueue.delete(route)
      
      this.currentPreloads++
      await this.executePreload(route)
      this.currentPreloads--
    }
  }

  async executePreload(routePath) {
    try {
      // 预加载组件
      const route = this.router.resolve(routePath)
      if (route.matched.length > 0) {
        const components = route.matched.map(match => match.components.default)
        await Promise.all(components.map(component => {
          if (typeof component === 'function') {
            return component() // 触发组件加载
          }
        }))
      }

      // 预加载关键数据
      await this.preloadRouteData(routePath)
      
      console.log(`✅ 预加载完成: ${routePath}`)
    } catch (error) {
      console.warn(`预加载失败 ${routePath}:`, error)
    }
  }

  shouldPreload(routePath) {
    // 检查路由是否支持预加载
    const route = this.router.resolve(routePath)
    return route.matched.some(record => 
      record.meta?.preload !== false
    )
  }

  setupIdlePreloading() {
    if ('requestIdleCallback' in window) {
      const idleCallback = () => {
        if (this.preloadQueue.size > 0) {
          this.processPreloadQueue()
        }
        requestIdleCallback(idleCallback)
      }
      requestIdleCallback(idleCallback)
    }
  }

  setupNetworkAwarePreloading() {
    // 网络状态感知预加载
    if (navigator.connection) {
      navigator.connection.addEventListener('change', () => {
        const connection = navigator.connection
        if (connection.saveData) {
          this.maxConcurrent = 0 // 省流量模式禁用预加载
        } else if (connection.effectiveType.includes('2g')) {
          this.maxConcurrent = 1 // 2G网络限制并发
        } else {
          this.maxConcurrent = 2 // 正常网络
        }
      })
    }
  }
}

4. Vue路由集成

// vue-router配置
const router = new VueRouter({
  routes: [
    {
      path: '/dashboard',
      component: () => import('./views/Dashboard.vue'),
      meta: {
        preload: true,
        importance: 0.9,
        preloadDependencies: ['/api/user/stats']
      }
    },
    {
      path: '/profile',
      component: () => import('./views/Profile.vue'),
      meta: {
        preload: true,
        importance: 0.7
      }
    },
    {
      path: '/settings',
      component: () => import('./views/Settings.vue'),
      meta: {
        preload: false // 明确不预加载
      }
    }
  ]
})

// 主应用集成
const behaviorTracker = new UserBehaviorTracker()
const predictor = new RoutePredictor(behaviorTracker)
const preloader = new SmartPreloader(predictor, router)

// Vue插件形式
const SmartPreloadPlugin = {
  install(Vue, { router }) {
    const tracker = new UserBehaviorTracker()
    const predictor = new RoutePredictor(tracker)
    const preloader = new SmartPreloader(predictor, router)
    
    Vue.prototype.$preloader = preloader
    Vue.prototype.$behaviorTracker = tracker
  }
}

Vue.use(SmartPreloadPlugin, { router })

5. 高级特性

// 基于机器学习的行为预测
class MLPredictor extends RoutePredictor {
  async trainModel() {
    // 使用历史数据训练预测模型
    const trainingData = this.collectTrainingData()
    const model = await this.trainRandomForest(trainingData)
    this.predictionModel = model
  }

  predictNextRoutes(currentRoute) {
    if (this.predictionModel) {
      return this.mlPredict(currentRoute)
    }
    return super.predictNextRoutes(currentRoute)
  }

  mlPredict(currentRoute) {
    const features = this.extractFeatures(currentRoute)
    return this.predictionModel.predict(features)
  }
}

// 渐进式预加载策略
class ProgressivePreloader extends SmartPreloader {
  getPreloadPriority(routePath) {
    const route = this.router.resolve(routePath)
    const basePriority = route.meta?.importance || 0.5
    
    // 根据用户行为调整优先级
    const behaviorBoost = this.calculateBehaviorBoost(routePath)
    const contextBoost = this.calculateContextBoost(routePath)
    
    return basePriority + behaviorBoost + contextBoost
  }

  calculateBehaviorBoost(routePath) {
    const hoverData = this.predictor.tracker.sessionData.hoverDurations.get(routePath)
    if (!hoverData) return 0
    
    const avgHover = hoverData.reduce((a, b) => a + b, 0) / hoverData.length
    return Math.min(avgHover / 2000, 0.3) // 最大提升30%
  }
}

性能优化策略

  1. 智能节流:避免过度预加载
  2. 内存管理:限制缓存大小
  3. 网络感知:根据网络条件调整策略
  4. 优先级队列:重要路由优先加载
  5. 缓存复用:充分利用浏览器缓存

监控和调优

class PreloadMonitor {
  constructor(preloader) {
    this.preloader = preloader
    this.metrics = {
      preloadHits: 0,
      preloadMisses: 0,
      timeSaved: 0
    }
    
    this.setupMonitoring()
  }

  setupMonitoring() {
    // 监控预加载命中率
    this.router.afterEach((to) => {
      if (this.preloader.wasPreloaded(to.path)) {
        this.metrics.preloadHits++
        console.log(`🎯 预加载命中: ${to.path}`)
      } else {
        this.metrics.preloadMisses++
      }
    })
  }

  getHitRate() {
    const total = this.metrics.preloadHits + this.metrics.preloadMisses
    return total > 0 ? this.metrics.preloadHits / total : 0
  }
}

这种智能预加载系统能够显著提升应用性能,通过学习和适应用户行为模式,在用户实际需要之前提前加载资源,创造无缝的用户体验。

posted @ 2025-10-19 17:07  阿木隆1237  阅读(16)  评论(0)    收藏  举报