1

I am using Server Sent Events (SSE) and my code to connect to my SSE backend looks like this:

function sseSubscribe() {
  events = new EventSource("/v1/sse/" + sseID + "/" + lastEventId);

  events.addEventListener("message", sseHeartbeat);
  events.addEventListener("error", sseError);
  events.addEventListener("reply", sseReply);
  events.addEventListener("refresh", sseRefresh);
}

This function is called to setup the initial SSE connection, but also when a reconnection is desired (because the connection broke for whatever reason).

On the server, if the lastEventId is greater than 0, it will stream any missing messages to the client.

So, hypothetically, if doing new EventSource() blocked, this wouldn't work, because the events would be streamed back to the browser before the corresponding event handlers (reply, refresh, etc.) were registered.

However, to my knowledge, this is not the case (I believe calling new EventSource is a non-blocking operation? Not sure though). However, I suppose it's possible if the user's computer was slow enough, and their connection was fast enough, that maybe missing messages could be streamed back before the listeners were registered.

Is this a reasonable fear, or should I feel relatively safe with the above code?

To reiterate, this code seems to work, but my fear is that messages may be streamed back from the new EventSource connection before the corresponding handlers are added. Is this reasonable, or does it have a 0% chance of happening?

Ryan Peschel
  • 11,087
  • 19
  • 74
  • 136
  • `new EventSource` is a normal, synchronous, blocking call, and that is exactly why it does work. You'll want to learn about the event loop. Have a look at [these](https://stackoverflow.com/q/48794320/1048572) [three](https://stackoverflow.com/q/31099598/1048572) [questions](https://stackoverflow.com/q/30906228/1048572) (while the latter two are about node.js, it works by the same principle in the browser) – Bergi Mar 12 '22 at 00:24
  • I'm confused by your reply. If it was synchronous, then wouldn't it _not_ work, because the response would occur before listeners were provided? In addition, are you sure it's synchronous? That would mean that if someone took 10 seconds to connect to an EventStream, the entire page's Javascript would be frozen in the interim. I don't think that's the case..? – Ryan Peschel Mar 12 '22 at 00:27
  • It's synchronous. It constructs an `EventStream` instance and immediately returns it. It does fire off the connection request, but it does not wait for the connection to succeed. The response may come in at any time then. When it does come in, the events are queued, regardless whether there's a listener for them already or not. The events are not actually dispatched until your code has finished executing, at which point it would have registered the listeners - they always get called and won't miss any events. – Bergi Mar 12 '22 at 00:37
  • Ah okay yeah I know it returns immediately but I thought you were also implying that the entire connection attempt was synchronous / blocked. Okay, I understand now. Thank you! – Ryan Peschel Mar 12 '22 at 00:39
  • It wouldn't work if the code was somehow asynchronous, and you'd register the listeners at an arbitrary time after creating (and connecting) the `EventStream`, because then the events might have been fired (and discarded, as they were no listeners yet) in between. – Bergi Mar 12 '22 at 00:39
  • Gotcha, makes sense. – Ryan Peschel Mar 12 '22 at 00:39

1 Answers1

2

The connection occurs after the current Javascript execution has completed. I believe this would be safe to assume for all browsers, though I don't have a definitive reference.

For example, Chrome starts the connection from a timer, which probably ties into the same event loop as, for example, setTimeout: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/eventsource/event_source.cc;l=99?q=EventSource&ss=chromium

Dark Falcon
  • 43,592
  • 5
  • 83
  • 98
  • Ah so you're saying it's guaranteed that even if hypothetically the server responded _instantly_ (which already wouldn't happen in practice), that the connection would occur on the next event loop iteration, so the callbacks would always be registered before the connection attempt began, regardless? – Ryan Peschel Mar 12 '22 at 00:37
  • That is correct. – Dark Falcon Mar 17 '22 at 16:25