jQuery ready method implementation

I left this question a long time ago, in time for the May Day holiday, let’s do a good research and summarize it.

  1. First of all, the difference between the ready method in jq and the onload method of window is mentioned here again. First of all, ready is only when the dom tree is loaded. Some img and other resources may not be loaded, but onload is all loaded successfully. And there can be multiple ready methods, while onload can only write one. There is another difference, I'll add it when I think of it.

  2. Generally, let us simulate a jq ready method by hand. I mostly write it like this:

     document.ready = function (callback) {
            ///兼容FF,Google
            if (document.addEventListener) {
                        document.addEventListener('DOMContentLoaded', function () {
                            document.removeEventListener('DOMContentLoaded', arguments.callee, false);
                            callback();
                        }, false)
                    }
             //兼容IE
            else if (document.attachEvent) {
                document.attachEvent('onreadystatechange', function () {
                      if (document.readyState == "complete") {
                                document.detachEvent("onreadystatechange", arguments.callee);
                                callback();
                       }
                })
            }
            else if (document.lastChild == document.body) {
                callback();
            }
        }

First detect the DOMContentLoaded event, and then revoke the binding. After triggering the callback, IE detects the onreadystatechange event. If document.readyState == "complete", the binding event is first undone, and finally the callback is triggered. Finally, it is a degeneration operation.

  1. The reason why the ready method appears is that the window.onload event is triggered after all the resources on the page are loaded. If there are large images and other resources on the page that respond slowly, the window.onload event will not be triggered. So DOM Ready appears Event. This event fires after the DOM document structure is prepared, i.e. before the resource is loaded.

  2. Generally in mainstream browsers, the DOMContentLoaded event can be used in many Webkit browsers and IE9. This event will be triggered after the DOM document is ready, which is included in the HTML5 standard. For browsers that support this event, using the DOMContentLoaded event directly is The simplest and best choice. But IE6, 7, 8 do not support the DOMContentLoaded event.

write picture description here

This is what is written in the above code. The first detection is the DOMContentLoaded event, and in old browsers or IE6-8, there is no way to hack:

  • The readyState also written above: If the browser has the document.onreadystatechange event, when the event is triggered, if document.readyState=complete, it can be considered that the DOM tree has been loaded.
    eg:
    //onreadystatechange event
    document.onreadystatechange = function(e){
        document.getElementById("divMsg").innerHTML += "<br/> onreadystatechange, readyState:" + document.readyState;
     
    };
  • doScroll detection: According to the IE browser documentation, when the page DOM is not loaded, an exception will occur when the doScroll method is called. (Microsoft's documentation points out that doScroll can only be triggered normally when the DOM main document is ready.) Then we use it in reverse. If it is not abnormal, then the page DOM is loaded, and we can continuously judge whether the DOM is loaded by whether doScroll can be executed.
    //doScroll
    var doScrollMoniterId = null;
    var doScrollMoniter = function(){
        try{
            document.documentElement.doScroll("left");
            document.getElementById("divMsg").innerHTML += "<br/>doScroll, readyState:" + document.readyState;
            if(doScrollMoniterId){
                clearInterval(doScrollMoniterId);
            }
        }
        catch(ex){
        }
    }
    doScrollMoniterId = setInterval(doScrollMoniter, 1);
  • setTimeout : The function triggered in setTimeout, which must be triggered after the DOM is ready.

    var setTimeoutReady = function(){
    document.getElementById("divMsg").innerHTML += "<br/> setTimeout , readyState:" + document.readyState;
    };
    var setTimeoutBindReady = function(){
    /in/.test(document.readyState)?setTimeout(arguments.callee, 1):setTimeoutReady();
    };
    setTimeoutBindReady();
  • External script: Implemented by setting the defer attribute of the script block. For details, see: link
  • Inner script: An improved version of the outer script. The outer script requires the page to reference an extra js file. The inner script method avoids this problem. See: link

Some of the above methods actually have problems. For example, when the readyState state is complete, the image has been loaded.
So a quote from a big guy is:
write picture description here

If you use doScroll specifically, I saw this way of writing last time:

//为了保证最后一定会调用ready方法,在上面每一种方式的最后都还是会为load事件绑定ready方法。
if ( document.readyState === "complete" ) {
      // Handle it asynchronously to allow scripts the opportunity to delay ready
      //这里的setTimeout是为了异步
      setTimeout( jQuery.ready, 1 );

    // Standards-based browsers support DOMContentLoaded
    //标准浏览器侦听事件接口:document.addEventListener
    } else if ( document.addEventListener ) {
      // Use the handy event callback
      document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

      // A fallback to window.onload, that will always work
      //文章一开始说了,这里为了保证一定会触发ready,所以还针对onload也绑定一次回调
      window.addEventListener( "load", jQuery.ready, false );

    // If IE event model is used
    } else {
      //IE侦听事件接口:document.attachEvent
      //如果有onreadystatechange事件,侦听之
      // Ensure firing before onload, maybe late but safe also for iframes
      document.attachEvent( "onreadystatechange", DOMContentLoaded );

      // A fallback to window.onload, that will always work
      window.attachEvent( "onload", jQuery.ready );


      // http://javascript.nwbox.com/IEContentLoaded/
      // 见下边说明
      // If IE and not a frame
      // continually check to see if the document is ready
      var top = false;

      try {
        top = window.frameElement == null && document.documentElement;
      } catch(e) {}

      //如果是IE并且不是iframe
      if ( top && top.doScroll ) {
        (function doScrollCheck() {
          if ( !jQuery.isReady ) {

            try {
              // Use the trick by Diego Perini
              // http://javascript.nwbox.com/IEContentLoaded/
              //一直调用doScroll滚动,因为DOM渲染结束前,DOM节点是没有doScroll方法的,所以一直会异常
              //直到DOM渲染结束了,这个时候doScroll方法不会抛出异常,然后就调用$.ready()
              top.doScroll("left");
            } catch(e) {
              return setTimeout( doScrollCheck, 50 );
            }

            // and execute any waiting functions
            jQuery.ready();
          }
        })();
      }
    }

The above code implements this process:
write picture description here

The implementation of jQuery source code is a little complicated, and it will continue to be supplemented after analysis and understanding.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325143980&siteId=291194637