SSE 消息发送优化技巧详解

简介

Server-Sent Events (SSE) 是一种基于 HTTP 的轻量级服务器推送技术,允许服务器通过 HTTP 建立一条持久的、单向的、从服务器到客户端的连接,实现服务器主动向客户端推送消息。SSE 利用浏览器的 EventSource 接口实现了服务器向客户端的长连接,相比较于传统的轮询和 WebSocket 技术,SSE 有着更低的网络开销和更简单易用的实现方式。在前端开发中,SSE 被广泛应用于实时通知、在线聊天、实时监控等场景。

问题

SSE 技术在使用过程中,可能会面临消息阻塞、连接断层等问题,降低了 SSE 的性能和用户体验。为了解决这些问题,我们需要使用一些优化技巧。

消息阻塞

SSE 通常采用下述方式将消息发送至前端:

function stream() {
  const source = new EventSource('/stream');
  source.onmessage = (event) => {
    console.log(event.data);
  }
  source.onerror = (event) => {
    console.error(event);
    source.close();
    setTimeout(stream, 1000);
  }
}

stream();

服务器通过不断地向客户端发送消息,客户端通过监听 onmessage 事件接收消息。但是,如果客户端无法及时处理接收到的消息,就会导致消息阻塞。这里,我们有两种方式来缓解这个问题:

消息队列

在 onmessage 中,不直接处理消息,而是将消息送入消息队列,由另外一个专门的线程负责执行。

const queue = [];
source.onmessage = (event) => {
  queue.push(event.data);
}

async function consume() {
  while (queue.length > 0) {
    console.log(queue.shift());
  }
  requestAnimationFrame(consume); // 下一个动画帧执行
}

consume();

消息合并

将多个消息合并成为一个消息进行传递,既减少了消息的数量又减少了阻塞的机会。

let pending = '';
source.onmessage = (event) => {
  if (event.data.endsWith('\n')) {
    console.log(pending + event.data.trim());
    pending = '';
  } else {
    pending += event.data;
  }
}

连接断层

在实际环境中,SSE 连接不断层也是常见问题之一,但是现阶段并没有确切的解决方案,我们只能通过一些技巧来避免这个问题。

心跳检测

在服务器发送空消息或者上一条消息的接受时间超过了一定时间间隔之后,通过发送特殊的消息来检测连接是否正常。

let lastHeartbeat = Date.now();
const INTERVAL = 10000; // 10s

source.onmessage = (event) => {
  lastHeartbeat = Date.now();
  console.log(event.data)
}

async function checkHeartbeat() {
  const now = Date.now();
  if (now - lastHeartbeat >= INTERVAL) {
    console.warn('heartbeat lost');
    source.close();
    setTimeout(stream, 1000);
  }
  setTimeout(checkHeartbeat, INTERVAL);
}

checkHeartbeat();

总结

本文主要介绍了 SSE 消息发送优化的技巧,包括消息队列、消息合并、心跳检测等。这些技巧能够提高 SSE 连接的性能和用户体验,但是不能完美解决消息阻塞和连接断层的问题,我们还需要通过其他手段来补充。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a7b389add4f0e0ff0d8d38


纠错反馈