智能预加载:基于用户行为和路由预测
核心概念
智能预加载通过分析用户行为模式、路由关系和页面重要性,在用户实际访问前预先加载资源,显著提升用户体验。
实现架构
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() - hoverStartthis.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 = behaviorTrackerthis.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 Nreturn 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.hoverDurationsfor (const [route, durations] of hoverData) {if (route !== currentRoute) {const avgDuration = durations.reduce((a, b) => a + b, 0) / durations.lengthconst score = this.normalizeHoverScore(avgDuration)predictions.set(route, score)}}return predictions}predictFromClickPatterns(currentRoute) {const predictions = new Map()const clickPaths = this.tracker.sessionData.clickPathsconst 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].pathconst to = recentClicks[i + 1].pathconst 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 = predictorthis.router = routerthis.preloadQueue = new Set()this.maxConcurrent = 2this.currentPreloads = 0this.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().valuethis.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.connectionif (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 = preloaderVue.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 0const avgHover = hoverData.reduce((a, b) => a + b, 0) / hoverData.lengthreturn Math.min(avgHover / 2000, 0.3) // 最大提升30%}
}
性能优化策略
- 智能节流:避免过度预加载
- 内存管理:限制缓存大小
- 网络感知:根据网络条件调整策略
- 优先级队列:重要路由优先加载
- 缓存复用:充分利用浏览器缓存
监控和调优
class PreloadMonitor {constructor(preloader) {this.preloader = preloaderthis.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.preloadMissesreturn total > 0 ? this.metrics.preloadHits / total : 0}
}
这种智能预加载系统能够显著提升应用性能,通过学习和适应用户行为模式,在用户实际需要之前提前加载资源,创造无缝的用户体验。