
本文介绍一种基于单次 ajax 请求 + 全局数据缓存的方案,解决大体积 json 数据(如 50,000+ 条记录)在网页中一次加载、多处复用的问题,避免重复请求,同时确保数据在 dom 加载后可被任意脚本安全访问。
本文介绍一种基于单次 ajax 请求 + 全局数据缓存的方案,解决大体积 json 数据(如 50,000+ 条记录)在网页中一次加载、多处复用的问题,避免重复请求,同时确保数据在 dom 加载后可被任意脚本安全访问。
在前端开发中,当需要将大量结构化数据(如 5 万条以上的员工工时记录)作为全局数据源供多个组件或模块使用时,“只加载一次、随处可用” 是核心诉求。直接在 <script> 标签中同步访问异步获取的 dataset 变量必然失败——因为 fetch() 是异步操作,而 console.log(dataset.length) 在请求完成前就已执行,此时变量尚未赋值。</script>
✅ 正确实践:封装加载逻辑 + 全局状态管理
推荐采用 “初始化即加载 + 回调/事件通知 + 全局只读引用” 的模式。以下是完整、可立即运行的解决方案:
1. 创建统一的数据加载器(data-loader.js)
// js/data-loader.js
let cachedData = null;
let loadingPromise = null;
// 全局函数:获取数据(自动缓存,多次调用返回同一 Promise)
window.getData = function() {
if (cachedData) return Promise.resolve(cachedData);
if (loadingPromise) return loadingPromise;
loadingPromise = fetch('./js/data.json')
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
return res.json();
})
.then(data => {
cachedData = data; // 永久缓存(内存中)
console.log(`✅ 成功加载 ${data.length} 条记录`);
return data;
})
.catch(err => {
console.error('❌ 数据加载失败:', err);
throw err;
});
return loadingPromise;
};
2. 在 HTML 中按需使用(无需等待 DOMContentLoaded)
<!-- index.html -->
<meta charset="UTF-8"><h2>工时数据看板</h2>
<div id="status">正在加载...</div>
<!-- 1. 首先加载数据加载器 -->
<script type="module">
import './js/data-loader.js';
</script><!-- 2. 立即使用(即使 DOM 未完全就绪,Promise 也会排队执行) --><script>
window.getData().then(data => {
document.getElementById('status').textContent =
`? 共加载 ${data.length} 条记录,首条:${data[0].Name}`;
// ✅ 此处可安全用于表格渲染、筛选、图表等
renderDataTable(data);
});
</script><!-- 3. 后续其他模块也可复用(零额外请求) --><script>
// 例如:另一个统计模块
window.getData().then(data => {
const totalHours = data.reduce((sum, item) => sum + item.Time, 0);
console.log(`? 总工时: ${totalHours} 小时`);
});
</script>
⚠️ 关键注意事项
- 不要跨 <script> 直接访问变量</script>:fetch() 返回 Promise,无法通过同步变量暴露结果;
- 避免硬编码路径:./js/data.json 需与实际部署路径一致,建议配合构建工具(如 Vite/Webpack)处理静态资源;
- 大文件性能提示:50,000+ 条 JSON 记录可能达数 MB,务必启用服务器 Gzip 压缩,并考虑分页/虚拟滚动(如使用 Tabulator 或 AG Grid);
- 错误防御:示例中已加入 HTTP 状态校验和 try/catch(.catch()),生产环境应增加重试机制或降级方案(如本地 mock);
- 现代替代方案:若项目支持 ES 模块,可将 getData 导出为默认函数,配合 import 使用,语义更清晰。
? 总结:用 Promise 封装异步加载 + 内存缓存是前端共享远程数据的黄金实践。它既保证了数据一致性,又彻底规避了竞态条件,且不依赖 jQuery 或任何第三方库——纯原生 JavaScript 即可稳健落地。











