Page 267 - Web性能权威指南
P. 267
var ws = new WebSocket('wss://example.com/socket');
ws.onopen = function () {
subscribeToApplicationUpdates(function(evt) { ➊
if (ws.bufferedAmount == 0) ➋
ws.send(evt.data); ➌
});
};
➊ 预订应用更新(如游戏状态更新)
➋ 检查客户端缓冲的数据量
➌ 如果缓冲是空的,发送下一次更新
前面的例子是要向服务器发送应用数据,但前提是客户端缓冲区已经没有之前待发
送的数据了。为什么非要做这个检查?所有 WebSocket 消息都会按照它们在客户端
排队的次序逐个发送。因此,大量排队的消息,甚至一个大消息,都可能导致排在
它后面的消息延迟——队首阻塞!
为解决这个问题,应用可以将大消息切分成小块,通过监控 bufferedAmount 的值来
避免队首阻塞。甚至还可以实现自己的优先队列,而不是盲目都把它们送到套接字
上排队。
很多应用都会生成多种消息:有高优先级的更新,也有低优先级的更新。
前者比如流量控制消息,后者比如后台传输。要实现最优化传输,应用必
须关心任意时刻在套接字上排队的是什么消息!
17.1.4 子协议协商
WebSocket 协议对每条消息的格式事先不作任何假设:仅用一位标记消息是文本还是
二进制,以便客户端和服务器有效地解码数据,而除此之外的消息内容就是未知的。
此外,与 HTTP 或 XHR 请求不同——它们是通过每次请求和响应的 HTTP 首部来
沟通元数据,WebSocket 并没有等价的机制。因此,如果需要沟通关于消息的元数
据,客户端和服务器必须达成沟通这一数据的子协议。
• 客户端和服务器可以提前确定一种固定的消息格式,比如所有通信都通过 JSON
编码的消息或者某种自定义的二进制格式进行,而必要的元数据作为这种数据结
构的一个部分。
• 如果客户端和服务器要发送不同的数据类型,那它们可以确定一个双方都知道的
消息首部,利用它来沟通说明信息或有关净荷的其他解码信息。
256 | 第 17 章