外观
请求竞态与实时通信
- 状态:未准备
- 适用方向:前端 / Go 全栈
- 最近复习:待填写
- 下次复习:待安排
一句话回答
异步结果应按会话、请求和业务版本判断是否仍有效,不能只按到达顺序覆盖状态;实时连接还需明确传输保证、业务确认、恢复策略和资源生命周期。
原理解释
搜索请求为什么会显示旧结果?
用户先搜 A 再搜 B,A 的响应可能更晚到达。防抖只减少请求,不保证已发请求的返回顺序。可以取消前次请求,并用请求序号或有效标志拒绝过期结果;取消不等于服务端业务操作已撤销。
js
let version = 0
async function search(query) {
const current = ++version
try {
const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`)
if (!response.ok) throw new Error(`HTTP ${response.status}`)
const data = await response.json()
if (current === version) renderResults(data)
} catch (error) {
if (current === version) renderError(error)
}
}
// renderResults/renderError 为页面提供的回调。轮询、SSE、WebSocket
- 轮询:兼容和实现简单,但存在重复请求与更新延迟。
- SSE:服务端到客户端的事件流,原生 EventSource 具有重连机制,但鉴权头等使用限制需考虑。
- WebSocket:双向消息通道,适合聊天、信令;浏览器原生 API 不自动实现应用级重连、重放或业务 ACK。
同一 WebSocket 连接内有传输顺序保证,不代表多个连接、多个异步处理链和多个引擎的业务结果具有统一顺序。断线后是否补齐、重发是否去重,都要应用协议定义。
场景与边界
心跳用于发现连接或对端状态异常,不能证明消息业务处理完成。重连通常需要退避、抖动、上限和鉴权重新确认;本地发送成功不代表服务端已落库。长时间高频消息还需观察 bufferedAmount、队列长度与内存,浏览器 WebSocket API 不提供自动背压控制。
项目中的应用
- SimulSpeak:按句子身份和阶段合并字幕,不让迟到 partial 覆盖已确认状态;具体受保护分支需沿测试确认。
- EinoTalk:区分本地乐观消息和服务端回显,避免重复追加。
- 自动重连、离线补偿和完整业务 ACK 是复习扩展,不能据此认定项目已经实现。
常见追问
- 如何避免重复消息? 使用稳定业务 ID 去重,规定临时 ID 与服务端 ID 如何对账,并保留必要状态。
- 如何验证竞态? 人工控制两个请求或事件的完成顺序,覆盖旧请求晚到、切会话、卸载和重复回显。
- WebRTC 与 WebSocket 什么关系? WebSocket 可承载信令,WebRTC 用于媒体或数据通道,两者职责不同。