EventSource
EventSource copied to clipboard
.close() does not abort current event source fetch connections
Fetch supports abort, if it is not provided or called it leaves long leaving TCP connections open. Abort package : https://www.npmjs.com/package/abortcontroller-polyfill
Example code/changes that could make this work:
-
Create a controller as described in https://www.npmjs.com/package/abortcontroller-polyfill
-
Add the abort signal to the call of
transport
transport.open(xhr, onStart, onProgress, onFinish, requestURL, withCredentials, requestHeaders, controller.signal);
- Store the controller in order to be able to access it in
close
es.controller = controller;
- Update close
EventSourcePolyfill.prototype.close = function () {
this.controller.abort();
this._close();
};
- Update the definition of
transport
when the browser supports fetch
FetchTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers, signal) {
// cache: "no-store"
// https://bugs.chromium.org/p/chromium/issues/detail?id=453190
var textDecoder = new TextDecoder();
fetch(url, {
headers: headers,
credentials: withCredentials ? "include" : "same-origin",
signal: signal
})
Why? reader.cancel()
is used to cancel the request. Doesn't it abort the connection?
Of course, it will not work unless the connection gets the "reading state", but it is not so bad, seems.
Abort package : https://www.npmjs.com/package/abortcontroller-polyfill "This "polyfill" doesn't actually close the connection when the request is aborted,"
Add the abort signal to the call of transport In fact, on line 439 - https://github.com/Yaffle/EventSource/blob/master/src/eventsource.js#L439 - the
onStartCallback
is called with a function that should stop the fetch request usingreader.stop()
.
Thanks
We did some experiments, and the connections never got closed when we were calling the .close()
.
It also does not seem to work when we tested with multiple event streams.
fetch(url, {
headers: headers,
credentials: withCredentials
? "include"
: "same-origin"
}).then(function(response) {
to my best understanding will wait for the fetch to complete and get a response before it gets cancelled, while the other approach will close it immediately. If we are not seeing something and it is already implemented, could you point us to a documentation or provide a small sample on how to close the event source when the component which created the event source gets destroyed?
It seems, the reader.cancel()
does not close the connection in Edge.
AbortController
also doesn't help.
try to use the Transport
option:
var es = new EventSource(url, {
Transport: XMLHttpRequest
});
I see no solutions with Fetch API
.
this:
fetch(url, {
headers: headers,
credentials: withCredentials ? "include" : "same-origin",
signal: signal
})
worked for me.
https://github.com/Yaffle/EventSource/commit/fd5408ef717b4679c186c80644dd46226176f03d - I have tried to use the suggested changes.
@Yaffle Thank you!
EventSourcePolyfill.prototype.close = function() {
this.controller.abort();
this._close();
};
I personally added the abort
to the es.close()
, so the user can call it at any time. However I do not understand the code enough to say if that is necessary. Will try to test your version tomorrow.
@svyotov , does it work? I have no Edge 18, but it does it work in Edge 17.
@Yaffle we decided to go with a different approach for other reasons, so unfortunately I will not be able to test it. Feel free to close the issue, and thank you for the help!
I have tested Edge 18 - it is still doesn't close connection when calling EventSource#close
with any AbortController or Reader#cancel
@Yaffle Hi,
I found out that before the server sends the 1st message, the initialization of EventSourcePolyfill
is not fully done (because onStart
never called) so the es.close()
doesn't abort the connection.
Also if the server sends the first message instantly it will be only handled by the client together with the second message.
I've done all tests with the latest Chrome(71), using EventSourcePolyfill
only
@requilence, hi Yes, this looks like a bug. I think, the solution here is to call cancelFunction in case the state is CLOSED. Or to add the AbortController. I would prefer the first, and send somethink from the server:-)
Thanks for the fast answer! You don't always have the ability to change the server's code :) Even if you have, there is always a possibility that user, for example, opens the route and then switch it(i mean with no page reload) before server answers on EventSource.
So it will be better to abort the connection with no response from the server.
Maybe return AbortController
from the transport.open
or add the onOpen
arg?
I did not want to use the AbortController as this is an extra entity and it is not supported on some browsers. Although, I will accept it.
I think, the open method may return a function which aborts the connection. And the AbortController polyfill will need to be updated (it will be needed to replace native fetch with a wrapper) to call reader cancel()
@requilence it is implemented now
Thanks a lot! I will be able to test it next week
any updates on this?
Hi, seems like it doesn't work. Tested on Chrome, latest version. Any workround ?