datafence通过守时、守全、守稳三机制解决h5首屏多异步请求超时雪崩问题:守时设全局超时窗口并支持per-key精细控制;守全区分critical/optional字段决定部分成功与否;守稳分层兜底(缓存→静态fallback→空结构),轻量ts实现仅约100行。

移动端 H5 的“超时雪崩”不是某个接口慢,而是多个异步请求在首屏初始化阶段同时发起、响应时间参差不齐,导致 UI 层因关键字段缺失反复重试或错误渲染,进而触发连锁失败。面向对象的自定义包装类(如 DataFence)正是为统一协调多路数据生命周期而设计,不靠阻塞等待,也不依赖 Promise.all/race 的二元逻辑,而是用可配置的守时、守全、守稳三机制,把不可控的并发变成可预期的数据交付边界。
守时:统一设定数据就绪窗口
所有并行请求共享一个全局超时阈值(例如 800ms),而非各自设 timeout。一旦窗口关闭,无论哪些请求还在 pending,都立即进入兜底流程。
- 避免某一路慢请求拖垮整页——比如地理位置接口卡在 2s,但用户信息、商品数据已在 300ms 返回,UI 本可提前渲染
- 超时后不抛错,而是交由栅栏自动注入 fallback 值,保证 render 函数能拿到完整 shape 的数据对象
- 支持 per-key 精细超时(如广告位仅给 300ms),但主窗口必须存在,作为兜底底线
守全:区分必填与可降级字段
明确声明哪些字段是页面渲染强依赖(critical),哪些可为空或用默认值替代(optional)。栅栏据此决定是否允许“部分成功”交付。
- critical 字段缺失 → 整体失败,触发重试或错误态(如 skeleton 持续显示)
- optional 字段超时/失败 → 自动填入预设值(如 ads: []、config: { theme: 'light' }),不影响主流程
- 字段声明写在配置里,而非散落在 fetch 调用中,便于灰度开关和 AB 实验
守稳:自动兜底 + 缓存协同
兜底不是简单 return {},而是分层决策:优先用 sessionStorage / localStorage 中的缓存值;无缓存则用编译期注入的静态 fallback;最后才返回空结构体。
- 例如用户信息字段失败时,先查 localStorage.getItem('user_cache'),再 fallback 到 { nick: '游客', avatar: '/default.png' }
- 配合离线包版本号做缓存 key 前缀,避免新包加载旧缓存引发样式错乱
- 兜底动作对上层透明,React/Vue 组件只管消费 data,无需 if-else 判断 loading/error
轻量实现要点(TypeScript)
一个典型 DataFence 类只需 100 行内,不依赖第三方库:
- 构造时接收 { critical: string[], optional: string[], timeout: number } 配置
- 提供 .wrap(key, promise) 方法,自动注册、计时、归集结果
- .then() 返回统一 shape 对象,字段值已按策略填充完毕
- 暴露 .abort() 接口,用于页面卸载或路由跳转时主动清理 pending 请求











