JavaScript的异步生成器是ES2018引入的特性,支持在函数执行过程中暂停并产出异步获取的值,而WebSocket是浏览器提供的全双工通信协议,适合服务端向客户端实时推送数据。将两者结合可以实现对实时数据流的异步迭代,让数据处理逻辑更清晰易维护。

核心概念铺垫
异步生成器基础
异步生成器函数通过async function*定义,内部使用await处理异步操作,通过yield产出值,调用后返回异步迭代器,可使用for await...of循环遍历产出的值。
下面是一个简单的异步生成器示例,模拟异步产出三个值:
async function* simpleAsyncGenerator() {
for (let i = 1; i <= 3; i++) {
// 模拟异步等待1秒
await new Promise(resolve => setTimeout(resolve, 1000));
yield i;
}
}
// 使用for await...of遍历
(async () => {
for await (const num of simpleAsyncGenerator()) {
console.log(num); // 依次输出1、2、3,每个间隔1秒
}
})();
WebSocket基础
WebSocket通过new WebSocket(url)创建连接,连接建立后可通过send方法发送数据,通过监听onmessage事件接收服务端推送的数据,连接关闭时触发onclose事件。
两者结合的实现思路
结合的核心是将WebSocket的消息接收逻辑封装到异步生成器中:当WebSocket接收到消息时,将消息作为yield的产出值;当WebSocket连接关闭时,终止生成器的执行。这样外部就可以通过for await...of循环逐条处理实时推送的数据,不需要嵌套回调或者复杂的事件监听逻辑。
完整实现示例
封装WebSocket为异步生成器
下面的代码实现了将WebSocket连接封装为异步生成器的函数,支持接收消息、处理错误和连接关闭的场景:
/**
* 将WebSocket连接封装为异步生成器
* @param {string} url - WebSocket服务地址
* @returns {AsyncGenerator} 异步生成器,产出服务端推送的消息
*/
async function* webSocketAsyncGenerator(url) {
// 创建WebSocket连接
const socket = new WebSocket(url);
// 用Promise包装连接打开事件,确保连接建立后再开始接收消息
const openPromise = new Promise((resolve, reject) => {
socket.onopen = () => resolve();
socket.onerror = (error) => reject(error);
});
await openPromise;
try {
// 用外部变量存储待产出的消息和对应的resolve函数
let resolveMessage = null;
let rejectError = null;
// 存储待处理的消息队列,处理消息到达速度快于迭代速度的情况
const messageQueue = [];
// 监听消息事件,将消息存入队列或触发resolve
socket.onmessage = (event) => {
if (resolveMessage) {
resolveMessage(event.data);
resolveMessage = null;
} else {
messageQueue.push(event.data);
}
};
// 监听错误事件
socket.onerror = (error) => {
if (rejectError) {
rejectError(error);
rejectError = null;
}
};
// 监听关闭事件,关闭时抛出结束信号
socket.onclose = () => {
if (resolveMessage) {
// 没有更多消息时,resolve一个特殊值表示结束,这里用null,实际可根据需求调整
resolveMessage(null);
resolveMessage = null;
}
};
// 循环产出消息
while (true) {
// 如果队列中有消息,先取出队列中的消息
if (messageQueue.length > 0) {
yield messageQueue.shift();
continue;
}
// 没有消息时,等待新消息到达
const message = await new Promise((resolve, reject) => {
resolveMessage = resolve;
rejectError = reject;
});
// 如果收到null,说明连接已关闭,结束生成器
if (message === null) {
return;
}
yield message;
}
} finally {
// 无论正常结束还是出错,都关闭WebSocket连接
if (socket.readyState === WebSocket.OPEN) {
socket.close();
}
}
}
使用异步生成器迭代实时数据流
下面是使用该异步生成器处理实时数据流的示例,假设WebSocket服务地址为ws://127.0.0.1:8080/stream:
(async () => {
try {
const streamUrl = 'ws://127.0.0.1:8080/stream';
// 遍历异步生成器产出的实时消息
for await (const message of webSocketAsyncGenerator(streamUrl)) {
console.log('收到实时数据:', message);
// 这里可以添加数据处理逻辑,比如解析JSON、更新页面状态等
try {
const data = JSON.parse(message);
console.log('解析后的数据:', data);
} catch (e) {
console.log('消息不是JSON格式,原始内容:', message);
}
}
console.log('WebSocket连接已关闭,数据流结束');
} catch (error) {
console.error('处理实时数据流出错:', error);
}
})();
方案优势与注意事项
- 逻辑更清晰:将实时数据的接收和处理逻辑用同步风格的循环编写,避免了回调嵌套的问题。
- 背压处理:通过消息队列可以处理消息推送速度快于消费速度的场景,不会丢失消息。
- 注意事项:需要确保WebSocket服务地址正确,同时处理连接失败、消息解析失败等异常情况;如果不需要接收消息后自动关闭连接,可以调整生成器的结束逻辑。
适用场景
这种结合方案适合需要持续接收服务端实时推送数据的场景,比如实时股票行情展示、即时聊天消息接收、物联网设备数据上报处理等,能够大幅简化实时数据流的代码复杂度。
JavaScript异步生成器WebSocket实时数据流异步迭代修改时间:2026-07-13 09:00:27