【小程序】订单数据缓存 以及针对海量库存数据的 懒加载+数据分片 的具体实现方式

订单数据缓存 以及针对海量库存数据的 懒加载+数据分片 的具体实现方式,结合UniApp+微信小程序的技术栈,分两部分详细拆解落地思路和核心代码,既讲逻辑也给可落地的实现方案。

一、订单数据缓存的实现(低网环境适配核心)

业务背景

汽配商户常处于仓库等低网/断网环境,开单过程中如果网络中断,已填写的订单数据不能丢失;网络恢复后需自动同步,因此缓存核心是「本地持久化+合理的同步策略」。

实现思路&核心代码

我基于微信小程序的本地存储API(wx.setStorageSync/wx.getStorageSync)封装了缓存工具类,结合「临时缓存+持久缓存+过期策略」实现,具体步骤如下:

1. 第一步:设计缓存策略
缓存类型 适用场景 存储位置 过期策略
临时缓存 订单草稿(未提交) 微信临时缓存 小程序退出后自动清理
持久缓存 已提交待同步的订单 微信本地持久存储 同步成功后删除,7天过期
2. 第二步:封装通用缓存工具类(核心复用)
typescript 复制代码
// utils/cache.ts - 统一管理缓存逻辑
/**
 * 订单数据缓存工具类
 * @param key 缓存键名(区分不同订单:order_draft_+开单员ID+时间戳)
 * @param data 要缓存的订单数据
 * @param isPersistent 是否持久缓存(默认临时)
 */
export const orderCache = {
  // 设置缓存
  set: (key: string, data: any, isPersistent = false) => {
    const cacheData = {
      data,
      timestamp: Date.now(), // 记录缓存时间,用于过期判断
      isPersistent // 标记是否持久缓存
    };
    // 临时缓存用wx.setStorage(异步),持久缓存用同步存储(确保数据落地)
    if (isPersistent) {
      wx.setStorageSync(`persist_${key}`, JSON.stringify(cacheData));
    } else {
      wx.setStorage({
        key: `temp_${key}`,
        data: JSON.stringify(cacheData),
        fail: () => {
          console.error('订单缓存失败,低网环境请注意手动保存');
        }
      });
    }
  },

  // 获取缓存
  get: (key: string, isPersistent = false) => {
    const cacheKey = isPersistent ? `persist_${key}` : `temp_${key}`;
    const cacheStr = isPersistent ? wx.getStorageSync(cacheKey) : wx.getStorageSync(cacheKey);
    if (!cacheStr) return null;

    const cacheData = JSON.parse(cacheStr);
    // 过期判断:持久缓存7天过期(604800000ms),临时缓存无过期但小程序退出失效
    if (isPersistent && (Date.now() - cacheData.timestamp) > 604800000) {
      this.remove(key, isPersistent); // 清理过期缓存
      return null;
    }
    return cacheData.data;
  },

  // 删除缓存(同步成功后调用)
  remove: (key: string, isPersistent = false) => {
    const cacheKey = isPersistent ? `persist_${key}` : `temp_${key}`;
    wx.removeStorageSync(cacheKey);
  },

  // 同步缓存订单到后端(网络恢复时触发)
  syncCacheOrder: async (key: string) => {
    const cacheOrder = this.get(key, true);
    if (!cacheOrder) return;
    try {
      // 调用后端同步接口
      const res = await uni.request({
        url: '/api/order/sync',
        method: 'POST',
        data: cacheOrder
      });
      if (res.data.code === 200) {
        this.remove(key, true); // 同步成功,删除缓存
        uni.showToast({ title: '订单同步成功' });
      }
    } catch (err) {
      console.error('订单同步失败,保留缓存:', err);
    }
  }
};
3. 第三步:业务层集成(开单页面)

在开单页面的输入、选择配件等操作时,实时缓存 数据;页面初始化时先读取缓存,避免数据丢失:

vue 复制代码
<!-- pages/order/create.vue -->
<script setup lang="ts">
import { orderCache } from '@/utils/cache';
import { ref, onMounted, onUnload } from 'vue';

// 订单唯一标识(开单员ID+当前时间戳)
const orderKey = `order_draft_${uni.getStorageSync('userId')}_${Date.now()}`;
// 订单表单数据
const orderForm = ref({
  partsList: [], // 配件列表
  customerInfo: {}, // 客户信息
  totalAmount: 0, // 总金额
  status: 'draft' // 草稿状态
});

// 页面初始化:读取缓存的订单草稿
onMounted(() => {
  const cacheData = orderCache.get(orderKey);
  if (cacheData) {
    orderForm.value = cacheData; // 恢复缓存的草稿数据
    uni.showToast({ title: '恢复离线草稿数据' });
  }
  // 监听网络状态,恢复网络时自动同步持久缓存的订单
  wx.onNetworkStatusChange((res) => {
    if (res.isConnected) {
      orderCache.syncCacheOrder(orderKey);
    }
  });
});

// 输入框/选择器变化时,实时缓存
const handleFormChange = () => {
  orderCache.set(orderKey, orderForm.value);
};

// 提交订单:转为持久缓存(待同步)
const submitOrder = () => {
  if (!uni.getNetworkType().networkType === 'none') {
    // 断网:持久缓存,标记待同步
    orderCache.set(orderKey, orderForm.value, true);
    uni.showToast({ title: '断网已保存,恢复网络后自动提交' });
  } else {
    // 有网:直接提交接口
    // ... 接口请求逻辑
  }
};
</script>
核心要点
  • JSON.stringify/parse 处理本地存储的序列化(小程序本地存储仅支持字符串);
  • 区分临时/持久缓存,避免无效数据占用存储;
  • 监听网络状态(wx.onNetworkStatusChange),实现断网缓存、联网自动同步。

二、库存数据懒加载+数据分片的实现(性能优化核心)

业务背景

库存数据量极大(49448品种/29728数量),一次性加载所有数据会导致页面卡顿、内存溢出,因此采用「后端分页(数据分片)+ 前端滚动懒加载」的方案,仅加载当前可视区域数据。

实现思路&核心代码
1. 第一步:后端接口改造(数据分片)

后端提供分页接口,接收 pageNum(页码)、pageSize(每页条数)参数,返回「当前页数据+总条数」,示例返回格式:

json 复制代码
{
  "code": 200,
  "data": {
    "list": [/* 每页库存数据 */],
    "total": 49448, // 总条数
    "pageNum": 1,
    "pageSize": 20
  }
}
2. 第二步:前端懒加载实现(滚动加载下一页)

基于UniApp的 onReachBottom(页面触底)生命周期,结合分页状态管理,实现滚动加载:

vue 复制代码
<!-- pages/stock/list.vue -->
<script setup lang="ts">
import { ref, onMounted, onReachBottom } from 'vue';
import { getStockList } from '@/api/stock'; // 库存列表接口

// 分页参数
const pageParams = ref({
  pageNum: 1,
  pageSize: 20,
  total: 0, // 总条数
  loading: false, // 加载中状态(防止重复请求)
  finished: false // 加载完成(无更多数据)
});
// 库存列表数据(仅存储已加载的分片数据)
const stockList = ref([]);

// 加载库存数据(分片请求)
const loadStockData = async () => {
  if (pageParams.value.loading || pageParams.value.finished) return;
  pageParams.value.loading = true;
  try {
    const res = await getStockList({
      pageNum: pageParams.value.pageNum,
      pageSize: pageParams.value.pageSize
    });
    // 拼接当前页数据(分片加载)
    stockList.value = [...stockList.value, ...res.data.list];
    // 更新分页状态
    pageParams.value.total = res.data.total;
    // 判断是否加载完成(无更多数据)
    if (stockList.value.length >= pageParams.value.total) {
      pageParams.value.finished = true;
    } else {
      pageParams.value.pageNum += 1; // 页码+1,准备加载下一页
    }
  } catch (err) {
    console.error('库存数据加载失败:', err);
  } finally {
    pageParams.value.loading = false;
  }
};

// 页面初始化:加载第一页
onMounted(() => {
  loadStockData();
});

// 页面触底:加载下一页(懒加载核心)
onReachBottom(() => {
  loadStockData();
});
</script>

<template>
  <view class="stock-list">
    <!-- 库存列表:仅渲染已加载的分片数据 -->
    <uni-list v-for="(item, index) in stockList" :key="index">
      <uni-list-item 
        title="{{item.partName}}" 
        note="库存数量:{{item.stockNum}}"
        show-arrow
      />
    </uni-list>
    <!-- 加载状态提示 -->
    <view v-if="pageParams.loading" class="loading">加载中...</view>
    <view v-if="pageParams.finished" class="finished">已加载全部库存</view>
  </view>
</template>
额外优化(可选):可视区域渲染

如果单页加载20条仍有卡顿,可结合 uni-virtual-list(虚拟列表),仅渲染当前屏幕可视区域的库存项,进一步降低DOM渲染压力:

vue 复制代码
<!-- 虚拟列表替代普通列表,仅渲染可视区域 -->
<uni-virtual-list
  :height="800" // 列表高度
  :item-height="80" // 每项高度
  :list="stockList" // 数据源
>
  <template v-slot:item="{ item }">
    <uni-list-item 
      title="{{item.partName}}" 
      note="库存数量:{{item.stockNum}}"
    />
  </template>
</uni-virtual-list>
核心要点
  • loading 状态防止「触底重复请求」,用 finished 状态标记「无更多数据」;
  • 数据分片核心是「后端分页+前端分批请求」,仅加载当前页数据;
  • 懒加载核心是「监听页面触底事件」,动态拼接数据,避免一次性渲染海量DOM。

总结

  1. 订单数据缓存:核心是「微信小程序本地存储+缓存策略」,区分临时/持久缓存,监听网络状态实现断网缓存、联网同步,保障低网环境操作流畅;
  2. 库存懒加载+数据分片:核心是「后端分页(数据分片)+ 前端触底懒加载」,结合loading/finished状态控制请求,可选虚拟列表进一步优化渲染性能,解决海量数据加载卡顿问题。

这两个方案既贴合UniApp+微信小程序的技术栈特性,也能在简历/面试中体现你对「性能优化」「边界场景(低网)」的思考,是汽配小程序这类ToB业务的核心优化点。

相关推荐
编程大师哥2 小时前
Java web
java·开发语言·前端
Murrays2 小时前
【React】01 初识 React
前端·javascript·react.js
大喜xi2 小时前
ReactNative 使用百分比宽度时,aspectRatio 在某些情况下无法正确推断出高度,导致图片高度为 0,从而无法显示
前端
helloCat2 小时前
你的前端代码应该怎么写
前端·javascript·架构
电商API_180079052472 小时前
大麦网API实战指南:关键字搜索与详情数据获取全解析
java·大数据·前端·人工智能·spring·网络爬虫
康一夏2 小时前
CSS盒模型(Box Model) 原理
前端·css
web前端1232 小时前
React Hooks 介绍与实践要点
前端·react.js
我是小疯子662 小时前
JavaScriptWebAPI核心操作全解析
前端
小二·2 小时前
Python Web 开发进阶实战:全链路测试体系 —— Pytest + Playwright + Vitest 构建高可靠交付流水线
前端·python·pytest