window.onload fires before jQuery document.ready in Firefox
Asked Answered
E

1

8

I created a Codepen showing the issue: https://codepen.io/samuelg0rd0n/pen/ExVGQEV

In Chrome, it correctly fires DOMContentLoaded event and jQuery document ready events before window onload events. However, in Firefox, the order is:

DOMContentLoaded
window.onload
$(window).on('load', function() { ... });
$(document).ready();
$(function() { ... });

Both window.onload and jQuery window onLoad are fired before jQuery document ready events. I'm pretty sure this must be some kind of bug either in jQuery or in Firefox. Can someone explain this to me? Thank you.

Chrome version: 81.0.4044.138

Firefox version: 75.0

Tried in both macOS and Linux with the same results.

Ermine answered 20/5, 2020 at 10:17 Comment(0)
R
5

This seems to be a jQuery issue. I've tested it this way:

  1. 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');
     });
    
  2. 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.

Rafi answered 26/1, 2021 at 9:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.