• jQuery-1.9.1源码分析系列(六) 延时对象应用——jQuery.ready


      还记不记得jQuery初始化函数jQuery.fn.init中有这样是一个分支

    //document ready简便写法$(function(){…})
    } else if ( jQuery.isFunction( selector ) ) {
        return rootjQuery.ready( selector );
    }

      所以$(fn)===$(document).ready(fn)

      来看一下jQuery.fn.ready的源码

    ready: function( fn ) {
        // Add the callback
        jQuery.ready.promise().done( fn );
    
        return this;
    }

      很明显在jQuery.ready.promise函数中设置了延时,当延时对象解决的时候执行fn函数。

      主要的处理流程:

      创建一个延时对象,并将文档准备好后的处理事件添加到该延时对象成功事件列表上

    jQuery.ready.promise = function( obj ) {
      if ( !readyList ) {
        readyList = jQuery.Deferred();

        ...

      } return readyList.promise( obj ); }

      添加文档准备状态的监听函数(jQuery.ready.promise函数片段)

        //标准浏览器支持DOMContentLoaded事件
        } else if ( document.addEventListener ) {
                //绑定DOMContentLoaded事件和响应函数,响应函数会解决延时
                document.addEventListener( "DOMContentLoaded", completed, false );
    
                //回退到window.onload事件绑定,所有的浏览器都支持
                window.addEventListener( "load", completed, false );
    
        //如果是IE事件模型
        } else {
                //确保在onload之前执行延时,可能时间比较迟,但是对于iframes来说比较安全
                document.attachEvent( "onreadystatechange", completed );
    
                //回退到window.onload事件绑定,所有的浏览器都支持
                window.attachEvent( "onload", completed );
    
                //如果IE并且不是一个frame
                //不断地检查,看是否该文件已准备就绪
                var top = false;
                try {
                    top = window.frameElement == null && document.documentElement;
                } catch(e) {}
                if ( top && top.doScroll ) {
                    (function doScrollCheck() {
                        if ( !jQuery.isReady ) {
                            try {
                                // Use the trick by Diego Perini
                                // http://javascript.nwbox.com/IEContentLoaded/
                                top.doScroll("left");
                            } catch(e) {
                                return setTimeout( doScrollCheck, 50 );
                            }
    
                            //移除之前绑定的事件
                            detach();
    
                            //执行延迟
                            jQuery.ready();
                        }
                    })();
                }
            }

      一旦监听到文档准备完成,则调用jQuery.ready执行延时对象的成功回调列表:即所有通过jQuery.ready(fn)【或jQuery(fn)】方式添加的函数fn。

    //ready事件处理函数
    completed = function( event ) {
        // readyState === "complete"在老版本IE上适用
        if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
            detach();
            jQuery.ready();
        }
    },
    //清除ready事件绑定
    detach = function() {
        if ( document.addEventListener ) {
            document.removeEventListener( "DOMContentLoaded", completed, false );
            window.removeEventListener( "load", completed, false );
    
        } else {
            document.detachEvent( "onreadystatechange", completed );
            window.detachEvent( "onload", completed );
        }
    };
    //处理当DOM准备完成
    jQuery.ready: function( wait ) {      
        ...        
        //设置DOM已经准备好的标志      
        jQuery.isReady = true;    
        ...   
        //执行绑定的延时事件   
        readyList.resolveWith( document, [ jQuery ] );   
        //触发任何绑定的就绪事件   
        if ( jQuery.fn.trigger ) {     
            jQuery( document ).trigger("ready").off("ready");   
        }  
    }

       整个过程就是如此。其中有一些小的知识点整理一下。

    a. 文档加载状态document.readyState


      document.readyState用来判断文档加载状态,是一个只读属性,可能的值有:

      0-uninitialized:XML 对象被产生,但没有任何文件被加载。
      1-loading:加载程序进行中,但文件尚未开始解析。
      2-loaded:部分的文件已经加载且进行解析,但对象模型尚未生效。
      3-interactive:仅对已加载的部分文件有效,在此情况下,对象模型是有效但只读的。
      4-complete:文件已完全加载,代表加载成功。

      实例:

    document.onreadystatechange = stateChange;//当页面加载状态改变的时候执行这个方法.
    function stateChange() {   
      
    if(document.readyState == "complete"){ //当页面加载状态为完全结束时进入     
        alert("文档加载成功")
      
      }
    }

      但是,老版本的Firefox并不支持document.readyState【最新的Firefox已经支持了】。所以想要兼容所有浏览器监听文档准备完成分两种情况来处理:

      - 标准浏览器使用addEventListener添加DOMContentLoaded和load监听,任何一个事件被触发即可

      - 老版本IE浏览器使用attachEvent添加onreadystatechange和onload来监听,任何一个被触发,并且onreadystatechange时document.readyState === "complete"即可。

      jQuery的处理也就是如此了

    jQuery.ready.promise = function(){
      ...
      //标准浏览器支持DOMContentLoaded事件
      else if ( document.addEventListener ) { //绑定DOMContentLoaded事件和响应函数,响应函数会解决延时 document.addEventListener( "DOMContentLoaded", completed, false ); //回退到window.onload事件绑定,所有的浏览器都支持 window.addEventListener( "load", completed, false ); //如果是IE事件模型 } else { //确保在onload之前执行延时,可能时间比较迟,但是对于iframes来说比较安全 document.attachEvent( "onreadystatechange", completed ); //回退到window.onload事件绑定,所有的浏览器都支持 window.attachEvent( "onload", completed );
           ...   } }
    //ready事件处理函数 completed = function( event ) { // readyState === "complete"在老版本IE上适用 if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { detach(); jQuery.ready(); } }

      

    b.doScroll检测文档加载完成


      这是Diego Perini 发现的一种检测IE是否加载完成的方式。详细链接

      原理是当页面 DOM 未加载完成时调用 doScroll 方法时会产生异常。那么不断的取检测异常是否发生就可以知道文档有没有加载完成。当没有发生异常,表明文档加载完成了。

                    (function doScrollCheck() {
                        if ( !jQuery.isReady ) {
                            try {
                                // Use the trick by Diego Perini
                                // http://javascript.nwbox.com/IEContentLoaded/
                                top.doScroll("left");
                            } catch(e) {
                                return setTimeout( doScrollCheck, 50 );
                            }
    
                            //移除之前绑定的事件
                            detach();
    
                            //执行延迟
                            jQuery.ready();
                        }
                    })();

     

  • 相关阅读:
    补间动画
    nginx+php的配置
    腾讯QQ首次在PC端采用气泡式聊天界面(from:36kr)
    mysql errno:13
    PHP高级面试题
    Nginx下fastcgi_split_path_info导致CodeIgniter配置问题
    ngx_http_fastcgi_module 的那些事
    PowerShell 定时刷新查看文件内容
    解决 VMWARE MAC 10.12无法全屏的问题
    libcurl 函数curl_easy_perform在release下崩溃的问题
  • 原文地址:https://www.cnblogs.com/chuaWeb/p/jQuery-1-9-1-Deferred3.html
Copyright © 2020-2023  润新知