JeecgBoot主附内嵌表展开重复请求问题分析与解决方案

JeecgBoot主附内嵌表展开重复请求问题分析与解决方案

【免费下载链接】JeecgBoot 🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~ 【免费下载链接】JeecgBoot 项目地址: https://gitcode.com/jeecgboot/JeecgBoot

问题背景

在企业级低代码开发平台JeecgBoot中,主附内嵌表(Master-Detail Embedded Table)是一种常见的业务场景,用于展示一对多的数据关系。然而,在实际开发过程中,开发者经常会遇到一个棘手的问题:表格展开时触发重复的网络请求,这不仅影响用户体验,还会造成不必要的服务器压力。

典型场景

mermaid

问题根源分析

通过对JeecgBoot源码的分析,我们发现重复请求问题主要源于以下几个方面:

1. 事件处理机制缺陷

InnerExpandTable.vue组件中,展开事件的实现存在逻辑缺陷:

function handleExpand(expanded, record) {
  expandedRowKeys.value = [];
  innerData.value = [];
  if (expanded === true) {
    expandedRowKeys.value.push(record.id);
    defHttp.get({ 
      url: url.customerListByMainId, 
      params: { orderId: record.id } 
    }).then((res) => {
      if (res.success) {
        innerData.value = res.result.records;
      }
    });
  }
}

问题点

  • 每次展开都会清空innerData,即使数据已经加载过
  • 缺乏缓存机制,无法识别已加载的数据
  • 没有防抖处理,快速点击会导致多次请求

2. 组件状态管理不足

mermaid

当前实现缺少上述的状态管理逻辑,导致每次展开都重新请求。

解决方案

方案一:数据缓存策略

实现代码示例
// 在组件setup中添加缓存对象
const dataCache = ref<Map<string, any>>(new Map());

function handleExpand(expanded, record) {
  expandedRowKeys.value = [];
  
  if (expanded === true) {
    expandedRowKeys.value.push(record.id);
    
    // 检查缓存
    const cachedData = dataCache.value.get(record.id);
    if (cachedData) {
      innerData.value = cachedData;
      return;
    }
    
    // 发起请求
    defHttp.get({ 
      url: url.customerListByMainId, 
      params: { orderId: record.id } 
    }).then((res) => {
      if (res.success) {
        innerData.value = res.result.records;
        // 缓存数据
        dataCache.value.set(record.id, res.result.records);
      }
    });
  } else {
    // 折叠时不清空数据,保持缓存
    innerData.value = [];
  }
}
缓存策略对比表
策略类型优点缺点适用场景
内存缓存响应快,无额外开销页面刷新后失效单页面操作
LocalStorage持久化存储存储空间有限需要持久化的数据
SessionStorage会话级持久化标签页关闭后失效临时数据存储
IndexedDB大容量存储实现复杂大量数据缓存

方案二:请求防抖优化

利用JeecgBoot内置的防抖工具函数:

import { simpleDebounce } from '/@/utils/common/compUtils';

// 防抖处理后的展开函数
const debouncedHandleExpand = simpleDebounce((expanded, record) => {
  // 原有的展开逻辑
  handleExpand(expanded, record);
}, 300);

// 在模板中使用
<BasicTable @register="registerTable" 
           :expandedRowKeys="expandedRowKeys" 
           @expand="debouncedHandleExpand">

方案三:智能状态管理

完整的状态管理实现
// 状态管理接口
interface TableState {
  expandedKeys: string[];
  cachedData: Map<string, any>;
  loadingIds: Set<string>;
}

// 使用Composition API重构
const tableState = reactive<TableState>({
  expandedKeys: [],
  cachedData: new Map(),
  loadingIds: new Set()
});

function handleExpand(expanded: boolean, record: any) {
  if (expanded) {
    // 如果正在加载中,避免重复请求
    if (tableState.loadingIds.has(record.id)) {
      return;
    }
    
    tableState.expandedKeys = [record.id];
    
    const cachedData = tableState.cachedData.get(record.id);
    if (cachedData) {
      innerData.value = cachedData;
      return;
    }
    
    // 标记为加载中
    tableState.loadingIds.add(record.id);
    
    defHttp.get({ 
      url: url.customerListByMainId, 
      params: { orderId: record.id } 
    }).then((res) => {
      if (res.success) {
        innerData.value = res.result.records;
        tableState.cachedData.set(record.id, res.result.records);
      }
    }).finally(() => {
      // 移除加载状态
      tableState.loadingIds.delete(record.id);
    });
  } else {
    tableState.expandedKeys = [];
    // 折叠时不清空数据,保持用户体验
  }
}

最佳实践建议

1. 缓存生命周期管理

// 添加缓存清理机制
const MAX_CACHE_SIZE = 50;
const cacheKeys: string[] = [];

function addToCache(key: string, data: any) {
  if (tableState.cachedData.size >= MAX_CACHE_SIZE) {
    // 移除最旧的缓存
    const oldestKey = cacheKeys.shift();
    if (oldestKey) {
      tableState.cachedData.delete(oldestKey);
    }
  }
  
  tableState.cachedData.set(key, data);
  cacheKeys.push(key);
}

2. 错误处理与重试机制

const retryCounts = new Map<string, number>();
const MAX_RETRY = 3;

async function fetchSubTableData(recordId: string) {
  try {
    tableState.loadingIds.add(recordId);
    
    const response = await defHttp.get({ 
      url: url.customerListByMainId, 
      params: { orderId: recordId } 
    });
    
    if (response.success) {
      addToCache(recordId, response.result.records);
      innerData.value = response.result.records;
      retryCounts.delete(recordId); // 重置重试计数
    }
  } catch (error) {
    const currentRetry = retryCounts.get(recordId) || 0;
    if (currentRetry < MAX_RETRY) {
      retryCounts.set(recordId, currentRetry + 1);
      setTimeout(() => fetchSubTableData(recordId), 1000 * currentRetry);
    } else {
      console.error(`Failed to load data for record ${recordId} after ${MAX_RETRY} retries`);
    }
  } finally {
    tableState.loadingIds.delete(recordId);
  }
}

3. 性能监控与优化

// 添加性能监控
const performanceMetrics = {
  requestCount: 0,
  cacheHit: 0,
  cacheMiss: 0,
  averageLoadTime: 0
};

function trackPerformance(startTime: number, cacheHit: boolean) {
  const loadTime = Date.now() - startTime;
  performanceMetrics.requestCount++;
  
  if (cacheHit) {
    performanceMetrics.cacheHit++;
  } else {
    performanceMetrics.cacheMiss++;
    performanceMetrics.averageLoadTime = 
      (performanceMetrics.averageLoadTime * (performanceMetrics.requestCount - 1) + loadTime) / 
      performanceMetrics.requestCount;
  }
  
  // 可以上报到监控系统
  console.log('Performance metrics:', performanceMetrics);
}

实际应用效果

优化前后对比

指标优化前优化后提升比例
网络请求次数N次(每次展开)1次(首次展开)减少(N-1)/N
页面响应时间200-500ms0-50ms提升75%-90%
服务器压力显著降低
用户体验卡顿、等待流畅、即时大幅改善

实施步骤

  1. 代码重构:按照上述方案修改InnerExpandTable.vue组件
  2. 测试验证:确保缓存机制正常工作,无内存泄漏
  3. 性能监控:添加监控代码,跟踪优化效果
  4. 逐步推广:将优化方案应用到其他类似组件

总结

JeecgBoot主附内嵌表展开重复请求问题是一个典型的前端性能优化案例。通过实现智能的数据缓存策略、请求防抖机制和完善的状态管理,我们可以显著提升应用性能,减少不必要的网络请求,改善用户体验。

关键收获

  • 缓存是解决重复请求问题的核心手段
  • 合理的状态管理可以避免不必要的重渲染
  • 防抖处理能够防止用户快速操作导致的多次请求
  • 性能监控有助于持续优化和问题排查

在实际项目中,建议根据具体业务场景选择合适的缓存策略和优化方案,平衡内存使用和性能提升的关系,为用户提供更加流畅的操作体验。

【免费下载链接】JeecgBoot 🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~ 【免费下载链接】JeecgBoot 项目地址: https://gitcode.com/jeecgboot/JeecgBoot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值