WebSocket消息接收可通过队列+Promise暂挂机制实现顺序消费:用messageQueue缓存消息、pendingResolves暂存resolve函数,nextMessage()返回Promise并按FIFO分发;需监听onclose/reject挂起Promise,并支持类型过滤与JSON解析。

WebSocket 的消息接收本身是事件驱动的,无法直接用 Promise 封装成“等待单条消息”的同步语义;但可以通过队列 + Promise 暂挂机制,把异步到达的消息按需分发给等待的 Promise,实现逻辑上的“顺序消费”。关键不是让 WebSocket 变同步,而是让使用者能以 Promise 风格按需取消息。
用消息队列暂存 onmessage 数据
创建一个数组作为消息缓冲队列,在 onmessage 中将每条 event.data 推入队列。同时维护一个等待中的 Promise 数组(或用 resolve 函数栈),每次有新消息就尝试匹配未决的 Promise。
- 避免丢消息:即使还没调用
await nextMessage(),消息也先存起来 - 避免竞态:多个
await nextMessage()调用不会互相覆盖,每个都应拿到独立消息 - 推荐用 FIFO 队列 + resolve 栈配对,比如 push 时检查是否有 pending resolve,有则立即 fulfill
封装 nextMessage() 返回可等待的 Promise
每次调用 nextMessage() 时,返回一个新的 Promise,并将其 resolve 函数存入待处理列表。若此时队列已有消息,立刻 resolve;否则等待下次 onmessage 触发时唤醒。
let messageQueue = [];
let pendingResolves = [];
socket.onmessage = (event) => {
messageQueue.push(event.data);
if (pendingResolves.length > 0) {
const resolve = pendingResolves.shift();
resolve(event.data);
}
};
function nextMessage() {
return new Promise(resolve => {
if (messageQueue.length > 0) {
resolve(messageQueue.shift());
} else {
pendingResolves.push(resolve);
}
});
}
注意事件循环与错误边界
WebSocket 关闭或出错时,所有挂起的 Promise 应被 reject,否则会永久 pending。需监听 onclose 和 onerror 并批量 reject pendingResolves。
-
socket.onerror通常不终止连接,建议只打日志,不 reject(除非明确连接已不可用) -
socket.onclose是必须处理的:清空 pendingResolves 并 reject,附带CloseEvent原因 - 可加超时控制:nextMessage(timeoutMs) 内无消息则 reject,避免无限等待
进阶:支持消息类型过滤与结构化解析
实际项目中消息常带 type 字段(如 "auth_ok"、"data_update")。可在 nextMessage() 上扩展选项,例如:
-
nextMessage({ type: 'ping' }):只等待指定 type 的消息 -
nextMessage({ json: true }):自动JSON.parse,失败则 reject - 内部仍走同一队列,只是 resolve 前做条件匹配,不满足则继续等待下一条
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











