In my website I have a page which sends some XHR requests to the same server, the problem is if the user click on any link to navigate to any other pages on the same server, the browser blocks and waits until all XHR finish first, then navigate, which can take ~10 seconds.
I already implemented the XHR abort solution, it’s working but the browser still waiting for XHR responses. In my opinion xhr.abort() is only to prevent calling xhr.onload() only, but in reality the browser still waiting for the response from XHR.
How can I force the browser to close and destroy an XHR request immediately using JavaScript?
Code is a copy-paste of this one.
All this is happens in the same server. If I navigate to another server the browser navigate immediately, while if the link is in the same server the browser wait first to finish all XHR requests.
Advertisement
Answer
The problem is that the browser limits the number of requests to a single origin, and apparently when navigating, Chrome (at least) waits until it can request the new page before tearing down the old one, resulting in the delay. (In constrast, Firefox does not wait, in my tests.)
If you cancel the requests that are outstanding when leaving the page, they stop preventing the browser from navigating. For instance, if you make your requests through a wrapper function:
const requests = new Set(); function request(...args) { const xhr = new XMLHttpRequest(...args); xhr.addEventListener("load", removeRequest); xhr.addEventListener("error", removeRequest); requests.add(xhr); return xhr; } function removeRequest() { requests.delete(this); }
…and then cancel them when leaving the page:
window.onbeforeunload = () => { for (const xhr of [...requests]) { xhr.abort(); requests.delete(xhr); } };
That solves the problem (for me, using Chrome; it also works on Firefox, but Firefox didn’t hold things up in the first place).
I wasn’t sure onbeforeunload
would work, given all the restrictions that are placed on it by modern browsers, but it did and I guess cancelling a request doesn’t try to start something new, and doesn’t take too long, so that makes sense.