zoukankan      html  css  js  c++  java
  • jQuery中的domReady分析

      我们都知道javascript中的window.onload方法的不足:必须等到所有图片和富文本媒体加载完后才能执行,影响用户体验。更好的做法是等到dom加载完即执行相应回调。类似jQuery中domReady方法应运而生。

      在jQuery中用这个方法非常简便:$(function(){}),这个其实是$(document).ready(function(){})的简便写法,见到源码:

    rootjQuery = jQuery(document);
    if ( jQuery.isFunction( selector ) ) {
      return rootjQuery.ready( selector );
    }

      在简单的背后,是jQuery进行了封装,屏蔽了很多兼容性问题。我们来看看原生的domReady事件,了解下有那些坑。

      1,w3c的DOMContentLoaded,想说爱你不容易。

      本来是个好方法,奈何对于IE6,7,8,只能呵呵了。

      2,setTimeout

      setTimeout设置的函数, 会在readyState为complete时触发, 但是触发时间点是在图片资源加载完毕后.

      3,readyState

      readyState为interactive时, DOM结构并没有稳定, 此时依然会有脚本修改DOM元素, readyState为complete时, 图片已经加载完毕

      4,外部script(通过设置script的defer属性实现)

      外部script:如果将此script放在页面上方, 则无法稳定触发. 并且触发时DOM结构依然可能发生变化.

      5,doScroll(微软的文档只出doScroll必须在DOM主文档准备完毕时才可以正常触发. 所以通过doScroll判断DOM是否准备完毕)

      doScroll通过时readyState可能为interactive, 也可能为complete. 但是一定会在DOM结构稳定后, 图片加载完毕前执行

      方法很多,比较杂乱。jQuery的方法还是比较可取的,监听各种触发条件。宁可错杀一千,绝不放过一个。

      来看看源码的实现:

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

    jQuery.ready.promise是个异步的Deffered对象,完成后触发回调fn。

    Deferred对象什么时候完成呢?最好的结果当然是dom加载完后马上触发。这个时候就是各种监听方法。

    jQuery.ready.promise = function( obj ) {
        if ( !readyList ) {
         readyList = jQuery.Deferred();
            // Catch cases where $(document).ready() is called after the browser event has already occurred.
            // we once tried to use readyState "interactive" here, but it caused issues like the one
            // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
            if ( document.readyState === "complete" ) {
                // Handle it asynchronously to allow scripts the opportunity to delay ready
                setTimeout( jQuery.ready );
    
            // Standards-based browsers support DOMContentLoaded
            } else if ( document.addEventListener ) {
                // Use the handy event callback
                document.addEventListener( "DOMContentLoaded", completed, false );
    
                // A fallback to window.onload, that will always work
                window.addEventListener( "load", completed, false );
    
            // If IE event model is used
            } else {
                // Ensure firing before onload, maybe late but safe also for iframes
                document.attachEvent( "onreadystatechange", completed );
    
                // A fallback to window.onload, that will always work
                window.attachEvent( "onload", completed );
    
                // 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) {}
            
                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 all dom ready events
                            detach();
    
                            // and execute any waiting functions
                            jQuery.ready();
                        }
                    })();
                }
            }
        }
        return readyList.promise( obj );
    };

    多少判断,多少绑定......首先是判断document.readyState。如果是等于complete,立即执行回到

    document.readyState === "complete"

    根据浏览器的不同,分别绑定:

    标准浏览器绑定:DOMContentLoaded,绑定load

    document.addEventListener("DOMContentLoaded", completed, false)

    window.addEventListener("load", completed, false)

    IE浏览器下

    document.attachEvent("onReadyStateChange", completed)

    window.attachEvent("load", completed)

    根据top.doScroll("left")判断是否加载完,加载完后直接触发:jQuery.ready();

    再来看看completed方法

    completed = function( event ) {
    
        // readyState === "complete" is good enough for us to call the dom ready in oldIE
        if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
            detach();
            jQuery.ready();
        }
    },

    还是触发jQuery.ready。最后来看看jQuery.ready

    ready: function( wait ) {
    
        // Abort if there are pending holds or we're already ready
        if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
            return;
        }
    
        // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
        if ( !document.body ) {
            return setTimeout( jQuery.ready );
        }
    
        // Remember that the DOM is ready
        jQuery.isReady = true;
    
        // If a normal DOM Ready event fired, decrement, and wait if need be
        if ( wait !== true && --jQuery.readyWait > 0 ) {
            return;
        }
    
        // If there are functions bound, to execute
        readyList.resolveWith( document, [ jQuery ] );
    
        // Trigger any bound ready events
        if ( jQuery.fn.trigger ) {
            jQuery( document ).trigger("ready").off("ready");
        }
    },

    最后还是要触发回调:readyList.resolveWith( document, [ jQuery ] );

    这个就是jQuery中domReady的实现。还是比较完美的。

    优点是:加入了异步回调之后结构非常优美,想在哪里触发就在哪里触发。而且几乎全兼容。

    缺点就是监听方法太多,对兼容性要求不高,不用这么费性能的方法。

     参考文档:http://www.cnblogs.com/zhangziqiu/archive/2011/06/27/DOMReady.html

  • 相关阅读:
    @RequestParam注解使用:Name for argument type [java.lang.String] not available, and parameter name information not found in class file either.
    cglib动态代理导致注解丢失问题及如何修改注解允许被继承
    springboot Autowired BeanNotOfRequiredTypeException
    git根据用户过滤提交记录
    不同包下,相同数据结构的两个类进行转换
    How to use Jackson to deserialise an array of objects
    jooq实践
    java如何寻找main函数对应的类
    Python--matplotlib
    Python 和 Scikit-Learn
  • 原文地址:https://www.cnblogs.com/pfzeng/p/4476580.html
Copyright © 2011-2022 走看看