Uncaught (in promise) DOMException
Closed this issue · 3 comments
F´ Version | F' GDS 2.0 |
Affected Component | loader.js |
Problem Description
On initial load or refresh of the page Chrome complains about the following error:
How to Reproduce
- From Chrome dev tool setting enable
Preserve Log
- Hard Refresh GDS by pressing Shift and Refresh button
- Observe Chrome error log in the dev tool
Expected Behavior
There should be no error when refreshing page
Root cause:
Chrome now disallows synchronous XHR during page dismissal when the page is being navigated away from or closed by the user. This involves the following events (when fired on the path of page dismissal): beforeunload, unload, pagehide, and visibilitychange.
Synchronous XHR is on the deprecation path. It hurts the end user experience.
The issue is the following:
The XMLHttpRequest
third argument is async: bool
. In the line above the async will be false when method is DELETE.
The destroy function is requesting a sync DELETE request (line 190 of loader.js) which is called from line 40 of gds.js during window.onbeforeunload
:
Confirmed that in the current GDS setup the DELETE session is not fired. Chrome ignores synchronous calls at onbeforeunload
event.
It seems there is no reliable way to inform the server when page is unloads.
Avoid unload and beforeunload
In the past, many websites have used the unload or beforeunload events to send analytics at the end of a session. However, this is extremely unreliable.
Modern Browsers ignore synchronous calls on beforeunload event. So there is no point to keep the following:
So the above should be changed to:
xhttp.open(method, endpoint + "?_no_cache=" + random + "&session=" + _self.session, true);
There are two ways to delete the session:
- One way to DELETE session is when Browser visibility is hidden:
document.addEventListener('visibilitychange', function logData() {
if (document.visibilityState === 'hidden') {
_loader.destroy();
}
});
The above will still not delete the session on unload, but it should be fine since the session ID will change after Browser refresh.
- Creating a no-op loop for several seconds:
window.addEventListener('beforeunload', function (e) {
_loader.destroy();
let counter = 0;
for (let i = 0; i < 1000000 ; i++){
counter += 1;
}
return counter;
});
The above will fire beforeunload event.
Closing this, says it was merged.