H5 实时数据流与断线恢复
H5 实时数据流与断线恢复
行情、聊天和任务进度等页面需要持续接收服务端变化。实时连接并不只是打开通道,还要处理首次快照、增量顺序、断线重连、页面后台、重复消息和高频渲染。可靠设计应把连接状态与业务数据状态分开,并让每条增量具备可验证的顺序。
一、抽象通道而不是散落连接代码
type ChannelState =
| { status: 'idle' }
| { status: 'connecting' }
| { status: 'connected' }
| { status: 'reconnecting'; attempt: number }
| { status: 'closed'; reason: string };
interface RealtimeChannel<Message> {
connect(): Promise<void>;
close(): void;
subscribe(listener: (message: Message) => void): () => void;
observeState(listener: (state: ChannelState) => void): () => void;
}
具体通道协议由基础层实现,业务页面只处理消息和稳定连接状态。
二、先快照后增量
页面首次进入通常先获取完整快照,再应用实时增量。如果先订阅后请求快照,快照可能覆盖期间收到的新数据;先请求后订阅,又可能漏掉中间变化。
常见做法是由服务端提供快照版本和增量序号,客户端以确定流程衔接:
- 建立通道并缓冲增量。
- 获取带版本的快照。
- 丢弃不新于快照的消息。
- 按序应用剩余增量。
- 进入实时状态。
具体顺序必须与服务端协议一致,客户端不能凭到达时间猜测。
三、使用序号识别重复与缺口
type QuoteUpdate = {
sequence: number;
symbol: string;
priceText: string;
};
function applyUpdate(state: QuoteState, update: QuoteUpdate): QuoteState {
if (update.sequence <= state.lastSequence) return state;
if (update.sequence !== state.lastSequence + 1) {
throw new SequenceGapError(state.lastSequence, update.sequence);
}
return state.applying(update);
}
重复消息可以忽略,发现缺口则重新同步快照或请求缺失范围。是否严格连续取决于协议。
四、重连使用退避与随机扰动
连接断开后立即无限重试,会在服务异常时制造请求风暴。可以逐步增加等待时间并加入小幅随机扰动,同时设置最大间隔。
function retryDelay(attempt: number, randomValue: number): number {
const base = Math.min(30_000, 1_000 * 2 ** attempt);
return base + Math.floor(randomValue * 500);
}
身份失效、协议拒绝等永久错误不应自动重连,应先完成相应业务处理。
五、页面后台时调整连接
移动浏览器进入后台后,计时器和网络可能被限制。返回前台时不能假设连接一直有效,应重新检查状态,并根据最后序号补齐数据。
低价值实时页面可以在后台主动断开,返回时重新建立。是否保持由业务实时性和资源成本决定。
六、心跳只验证连接活性
心跳可以发现长时间无数据但已经失效的连接。它不证明业务数据完整,序号和快照仍是数据一致性的依据。
心跳间隔由基础通道和服务端共同约定,不能每个页面自行设置。页面销毁时必须停止相关计时器。
七、合并高频视觉更新
业务层可以完整应用每条消息,界面层按帧或业务允许的周期渲染最新快照。
let pendingRender = false;
function scheduleQuoteRender(): void {
if (pendingRender) return;
pendingRender = true;
requestAnimationFrame(() => {
renderQuotes(quoteStore.snapshot());
pendingRender = false;
});
}
交易确认等必须逐条展示的事件不能被普通采样策略丢弃。
八、限制内存和消息积压
页面阻塞或后台暂停时,消息队列可能增长。可以为缓冲区设上限,并在超过能力时丢弃可合并的旧状态消息或重新请求快照。
不能无差别丢弃命令型事件。消息类型需要明确哪些是状态覆盖,哪些是不可丢失事实。
九、订阅必须可解除
subscribe 返回解除函数,组件销毁时调用。重复进入页面如果没有解除,会出现同一消息处理多次并泄漏页面对象。
多个组件共享同一通道时,由连接管理器做引用计数或应用级持有,组件不直接决定全局连接何时关闭。
十、测试时序
使用可控通道替身验证:
- 快照期间到达的增量不会丢失。
- 重复序号不会重复应用。
- 序号缺口触发重新同步。
- 永久错误不无限重连。
- 页面后台返回后补齐数据。
- 高频消息完整进入数据层但按计划渲染。
- 组件销毁后不再收到回调。
总结
实时数据可靠性来自快照、序号和恢复协议,而不是连接长时间不断。将通道状态与业务状态分开,按序应用增量,重连使用有边界退避,并在页面后台与高频场景控制资源,才能让实时页面既及时又一致。
- 点赞
- 收藏
- 关注作者
评论(0)