本节摘要:Ajax 是"客户端拉"的模型——页面问、服务器答。但越来越多场景需要反过来:服务端推。本节对比四条通信通道(轮询、长轮询、SSE、WebSocket)的原理、开销与适用边界,给出一张选型雷达;再看 HTTP/2 与 HTTP/3 对 Ajax 链路的改变(多路复用、连接迁移),最后回到概念本身——"Ajax"这个词正在被重新定义成什么。
做一个小需求:聊天页面要实时显示"对方正在输入……"。用 Ajax 的思路,最朴素的实现是定时器每两秒问一次服务器"有新状态吗"。做完发现能用,但三个问题随之而来:延迟(最坏两秒才看到状态,够尴尬);浪费(大部分询问的回答是"没有",白跑);放大(一万个在线用户就是每秒五千次无效请求,服务器在为"没有"工作)。
这个需求暴露的是 Ajax 模型的先天边界:一问一答。服务器永远无法主动开口——它知道"对方开始输入了",却只能等页面来问。所有"实时感"的需求,都要在这个约束下找变通或找替代。
四条通道就是四种回答。

短轮询就是开头的定时器方案,setInterval 加 GET。它的工程要点在细节:间隔的权衡(间隔短则实时但浪费,间隔长则省资源但迟钝——按需求定,状态类 2 到 5 秒、监控类 30 秒都很正常);用 setTimeout 链代替 setInterval(setInterval 不等上一次的响应,慢网络下请求会堆积——链式写法保证"答完再问下一轮"):
async function poll() { try { const state = await request('/api/chat/typing-state'); updateTypingIndicator(state); } finally { setTimeout(poll, 2000); // 无论成败 下一轮照常 简单健壮 } } poll();
短轮询的合理领地:低频、可容忍秒级延迟、且本就要刷新数据的状态(仪表盘数字、任务进度)。它的隐性优势别忽略——纯 HTTP、无状态、服务端零改造、浏览器兼容无死角,是成本最低的准实时。
长轮询把间隔的浪费变成挂起的等待:页面发请求,服务器不立即答,持着连接直到有新数据(或超时约 30 秒)才响应;页面一收到立刻再发下一个。实时性接近推送,而链路仍是普通 HTTP——它曾是 SSE 与 WebSocket 普及前的主流实时方案,老牌即时通信的网页版多数走过这条路。
代价:服务端要维护大量挂起连接(每个在线用户占一条),需要专门的超时管理与连接复用设计;断线检测与重连退避(4.4 节的退避思想直接复用)要前端自理。今天新建项目,长轮询基本只在基础设施不支持 SSE 与 WebSocket 时的兜底场景出现。
服务器推送事件(Server-Sent Events)是 HTTP 协议内的标准推送通道:页面建立一条普通 HTTP 连接,服务器以事件流的形式持续写入,浏览器端以事件回调接收。使用侧出奇地轻:
const es = new EventSource('/api/notifications/stream'); es.onmessage = e => { // 默认 message 事件 const notice = JSON.parse(e.data); showToast(notice.title); }; es.addEventListener('order-updated', e => { // 命名事件通道 updateOrderBadge(JSON.parse(e.data)); }); es.onerror = () => { /* 自动重连由浏览器负责 这里只处理 UI 态 */ };
SSE 的三张好牌:自动重连内建(断线后浏览器自动带最后事件标识重连,服务端可续传——WebSocket 的重连要自己写);走纯 HTTP(代理、网关、鉴权、负载均衡全按普通请求处理,运维零特殊心智);事件协议简单(文本行协议,data 加 event 加 id,调试可直接看流)。
边界也明确:单向(只能服务器到客户端,页面上行还得靠普通 Ajax——这也是常见组合:SSE 收、POST 发);浏览器连接数有历史限制(HTTP/1.1 下同域约六个,HTTP/2 下不是问题——又一个升级 HTTP/2 的理由)。
适配场景一句话:只要"服务器到页面"的单向流够用,SSE 多半是性价比最高的答案——通知中心、行情报价、构建日志、AI 流式回复的逐 token 输出,都是它的主场。
WebSocket 从 HTTP 握手升级而来,之后变成一条独立的双向长连接:两端随时互发消息,没有请求响应的配对关系。适合高频双向的场景:聊天、多人协同编辑、实时对战游戏、金融交易终端。
它的成本清单要诚实列出:服务端要专门支持(长连接的进程模型与传统请求响应式服务不同,水平扩容要配消息网关或订阅发布层);心跳与重连自理(SSE 白送的能力这里全部手写——心跳检测假死连接、退避重连、重连后的状态恢复);一切自己设计(消息格式、确认机制、顺序保证,HTTP 免费给你的东西这里都是自选题)。
浏览器侧的使用骨架:
const ws = new WebSocket('w' + location.origin.slice(4) + '/ws/chat'); ws.onopen = () => heartbeat.start(); // 心跳 防假死 ws.onmessage = e => handleFrame(JSON.parse(e.data)); ws.onclose = () => { heartbeat.stop(); setTimeout(reconnect, backoff.next()); // 退避重连 4.4 节思想复用 };
选型误区的提醒:很多团队为"显得实时"给低频场景上 WebSocket——通知一分钟一条的场景,长连接的心跳、运维、状态恢复成本全部白付,SSE 或轮询就能体面解决。双向高频才是 WebSocket 的门票,单向流是 SSE 的主场,低频状态是轮询的舒适区。
Ajax 的日常体验也随 HTTP 协议版本悄悄变化。HTTP/1.1 的时代:浏览器对同域并发连接约六个,多请求排队(4.1 节瀑布图的堆叠病症),域名分片与雪碧图是那个时代的补丁。HTTP/2:一条连接多路复用,请求不再排队抢连接(并发上限问题大幅缓解);头部压缩省重复头;但队头阻塞在应用层仍可能发生(某个慢响应占住流)。HTTP/3(QUIC):传输层换到 UDP,连接迁移(网络切换不断链)与更快的握手,移动端弱网切换的体验红利最大。
对开发者的实际影响:域名分片与请求合并的部分理由消失了(4.1 节"合并"的收益要重新评估——HTTP/2 下小请求的成本变低);SSE 的六连接限制解除;并发池的默认值可以放宽。但减少请求体积与数量的优化原则从不过时——协议提速的是传输,不是"传不必要的数据"的浪费。
回头看术语的漂移轨迹:2005 年它特指"用 XHR 做异步局部更新";后来 Fetch 取代 XHR、框架接管渲染,人们仍把"浏览器里异步取数"统称为 Ajax;再后来"取数"本身也被抽象化——在请求状态库里你声明的是数据需求(queryKey 加 queryFn),传输细节退到底层。
两件事在同步发生:机制的泛化(Ajax 从"一项技术"变成"一类行为"的代称,就像"打车"不再特指招手)与关注点的上移(从怎么发请求,到怎么管理服务端数据、怎么编排用户与数据的同步)。但中心问题一以贯之——第 1 章开头的那个:让界面与服务器数据保持同步,同时不打断用户。XHR、Fetch、SSE、WebSocket 是这个问题的四代答案,大概率不会是最后四代。掌握问题的结构(拉与推、同步与异步、状态与传输)的人,接得住第五代。
SSE 走 HTTP,Cookie 与网关鉴权天然可用;EventSource 自定义头不方便(可通过查询参数或 Cookie 传递令牌)。WebSocket 握手阶段是 HTTP(可带 Cookie 与头),升级后的消息帧里就要靠应用层协议自己做鉴权与续期了。
轮询按"在线用户数除以间隔"算请求速率;长轮询按在线数算并发挂起连接数(对内存与连接数上限敏感);SSE 与 WebSocket 同为长连接,但 SSE 只发不收,帧协议开销更小。选型前拿真实在线规模对一遍这三本账。
三个方向任选:往前端框架的数据层深挖(请求状态库的缓存与失效设计)、往 Node 服务端(接口的另一端)、往实时系统(长连接架构与消息队列)。三条路都会不断回头用到本教程的东西——错误分类、竞态防护、缓存策略、事件循环,是它们的公共地基。
用三个虚构需求做结业演练,每个先自己选通道、写理由、再对参考。需求一:工厂看板要显示设备温度,每三十秒刷新一次,页面常驻大屏。参考:短轮询。理由是低频加可容忍延迟加零服务端改造——大屏场景连断线重连都简单(刷新页面即可),上推送纯属浪费。骨架就是本章的 setTimeout 链加页面可见性暂停。
需求二:文档协作工具,多人同时编辑,光标与内容要秒级同步。参考:WebSocket。双向高频是硬需求(本地编辑要上行、他人编辑要下行),没有更轻的替代。骨架是长连接加心跳加退避重连加消息确认协议——本章指出了成本清单,实现细节够再写一本书,但知道它贵在哪、什么场景才配用,正是选型课的毕业标准。
需求三:订单页要显示物流状态更新,用户停留期间保持较新。参考:SSE 或分钟级轮询皆可,看团队基建——有推送网关就用 SSE(单向流、自动重连白送),没有就用两分钟轮询(物流更新对分钟级延迟无感)。这个需求的考点是克制:它看起来"想要实时",实际上不需要,识别这一点比技术实现更重要。
三个需求合起来考察的是同一件事:把"实时感"拆成延迟容忍度、方向、频率三个参数,再拿参数对表选通道。能稳定完成这个拆解,你就不会被任何新通信技术的营销词晃到——每个新通道出世时,先问它优化了三个参数里的哪一个、代价是什么,答案自然浮现。这也是整套教程的最后一条心法:技术会继续更新,参数表不会。带着这张表毕业的人,下一轮技术潮水涌来时,别人在背新名词,你在核对参数——从容,来自把变化还原为不变结构的能力。这本教程从一次白屏讲到四条通信通道,讲的所有具体技术都会老去,但"从一个真实问题出发、理解机理、再做工程取舍"的走法不会——愿它跟着你走过下一批、再下一批的新名字,直到你也开始给别人画参数表的那一天。