nasa/fprime-gds

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:

Screen Shot 2021-08-15 at 12 06 26 AM

How to Reproduce

  1. From Chrome dev tool setting enable Preserve Log
  2. Hard Refresh GDS by pressing Shift and Refresh button
  3. 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.

See reference

The issue is the following:

https://github.com/fprime-community/fprime-gds/blob/733010ce30a478ed53b755173c9f46797271b4e5/src/fprime_gds/flask/static/js/loader.js#L137

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:

https://github.com/fprime-community/fprime-gds/blob/733010ce30a478ed53b755173c9f46797271b4e5/src/fprime_gds/flask/static/js/loader.js#L186-L191

https://github.com/fprime-community/fprime-gds/blob/733010ce30a478ed53b755173c9f46797271b4e5/src/fprime_gds/flask/static/js/gds.js#L39-L41

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.

See MDN reference

Modern Browsers ignore synchronous calls on beforeunload event. So there is no point to keep the following:

https://github.com/fprime-community/fprime-gds/blob/733010ce30a478ed53b755173c9f46797271b4e5/src/fprime_gds/flask/static/js/loader.js#L137

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:

  1. 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.

  1. 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.

Screen Shot 2021-08-15 at 9 00 12 AM

Closing this, says it was merged.