This seems to be a jQuery issue. I've tested it this way:
When I use vanilla JS functions, I get the correct order in firefox (first fires DOM Ready and then window load):
document.addEventListener('DOMContentLoaded', function(event) {
console.log('DOMContentLoaded');
});
window.addEventListener('load', function(event) {
console.log('window load');
});
When I use jQuery, I get the wrong order (first fires window load and then DOM Ready):
$( window ).on( 'load', function() {
console.log('window load');
});
$(function () {
console.log('DOM Ready');
});
Note: such a wrong order happens only when resources are cached and Web Console is closed.
The same way you can verify the correct order of firing events by running this code:
document.addEventListener('readystatechange', function(event) {
console.log( 'readystatechange', document.readyState );
});
In firefox, it always fires "interactive" state first (e.g. DOMContentLoaded) and then "complete" (e.g. window load).
Therefore, it's not the DOMContentLoaded event firing before the window load event, it's jQuery's DOM ready event handler fires before the window load event for some reason.
This was tested on jQuery version 3.5.1 which is the latest now. Firefox version 82.0.3 (64-bit) running on Mac.
For now, I'm using a simple workaround by adding a flag variable and check it in jQuery's DomReady event. If the window has been loaded already when jQuery's DOM Ready event fired, I run my functions that have to run on window load again. It's not ideal or elegant but totally satisfies simple web page scripts.
var windowLoaded = false;
$( window ).on( 'load', function() {
windowLoaded = true;
runMyWindowLoadFunctions();
} );
$(function() {
if ( windowLoaded ) {
// Beware, runMyWindowLoadFunctions will run twice
runMyWindowLoadFunctions();
}
});
UPDATE
Just checked the jQuery sources code for the ready event https://github.com/jquery/jquery/blob/master/src/core/ready.js
// The ready event handler and self cleanup method
function completed() {
document.removeEventListener( "DOMContentLoaded", completed );
window.removeEventListener( "load", completed );
jQuery.ready();
}
// Catch cases where $(document).ready() is called
// after the browser event has already occurred.
if ( document.readyState !== "loading" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
window.setTimeout( jQuery.ready );
} else {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", completed );
// A fallback to window.onload, that will always work
window.addEventListener( "load", completed );
}
As you can see, there could be a case when the window load event is fired before jQuery script has been processed and in this case, jQuery is running "ready" event handlers.
As far as I understand, jQuery is not checking if its "ready" event handler has been fired before it runs window load event handlers.