javascriptjqueryjquery-3

jQuery's function $(function())’s execute order when the $(function()) called more one times


Code like this:

$(window.document).ready(function () {
    window.alert('alert 1');
});

$(function () {
    window.alert('alert 2');
});

$(function () {
   window.alert('alert 3');
});
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo2</title>
    <script src="https://unpkg.com/jquery@3.1.1/dist/jquery.js"></script>
    <script src="demo2.js"></script>
</head>
<body>

</body>
</html>

when i execute the above code, the page' alert order sometimes is: alert 1, alert 2, alert 3, and sometimes is: alert 1, alert 3, alert 2. could anyone tell my why?


Solution

  • At lines 3930 through 3947 jQuery version 3.1.1 handles .ready() being called after document has already loaded. At line 3938 jQuery.ready is called inside of setTimeout without a duration set with attached comment

    // Handle it asynchronously to allow scripts the opportunity to delay ready
    

    which would explain how window.alert('alert 3') could potentially be called before window.alert('alert 2')


    // Catch cases where $(document).ready() is called
    // after the browser event has already occurred.
    // Support: IE <=9 - 10 only
    // Older IE sometimes signals "interactive" too soon
    if ( document.readyState === "complete" ||
        ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
    
        // Handle it asynchronously to allow scripts the opportunity to delay ready
        window.setTimeout( jQuery.ready ); // Line 3938
    
    } else {
    
        // Use the handy event callback
        document.addEventListener( "DOMContentLoaded", completed );
    
        // A fallback to window.onload, that will always work
        window.addEventListener( "load", completed );
    }
    

    The following stacksnippet should reproduce result described by OP

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Demo2</title>
      <script src="https://code.jquery.com/jquery-3.1.1.js"></script>
      <script>
        $(window.document).ready(function() {
          window.alert('alert 1');
        });
    
        $(function() {
          window.alert('alert 2');
        });
    
        $(function() {
          window.alert('alert 3');
        });
      </script>
    </head>
    
    <body>
    
    </body>
    
    </html>

    See also completed function at Line 3924

    // The ready event handler and self cleanup method
    function completed() {
        document.removeEventListener( "DOMContentLoaded", completed );
        window.removeEventListener( "load", completed );
        jQuery.ready();
    }
    

    See plnkr http://plnkr.co/edit/C0leBhYJq8CMh7WqndzH?p=preview at version 1


    Edit, Updated

    To ensure the order of execution of functions at .ready() you can return a promise from the function calls, use .then() inside single .ready() call to call functions defined globally or previously within .ready() handler.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Demo2</title>
      <script src="https://code.jquery.com/jquery-3.1.1.js"></script>
      <script>
        function ready1(wait, index) {
          // do stuff
          return new Promise(resolve => {
              setTimeout(() => {
                window.alert('alert ' + index);
                resolve(index)
              }, wait)
            })
            .then((i) => console.log(i))
        }
    
        function ready2(wait, index) {
          // do stuff
          return new Promise(resolve => {
              setTimeout(() => {
                window.alert('alert ' + index);
                resolve(index)
              }, wait)
            })
            .then((i) => console.log(i))
        }
    
        function ready3(wait, index) {
          // do stuff
          return new Promise(resolve => {
              setTimeout(() => {
                window.alert('alert' + index);
                resolve(index)
              }, wait)
            })
            .then((i) => console.log(i))
        }
        $().ready(function() {
          ready1(3000, 0) 
          .then(function() {
            return ready2(1500, 1) 
          })
          .then(function() {
            return ready3(750, 2) 
          });
        })
      </script>
    </head>
    
    </html>