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

  • 相关阅读:
    bzoj4518[Sdoi2016]征途 斜率优化dp
    bzoj3675[Apio2014]序列分割 斜率优化dp
    bzoj3437小P的牧场 斜率优化dp
    bzoj3156防御准备 斜率优化dp
    bzoj1911[Apio2010]特别行动队 斜率优化dp
    bzoj5100 [POI2018]Plan metra 构造
    bzoj1597[Usaco2008 Mar]土地购买 斜率优化dp
    刷题总结——Middle number(ssoj 优先队列)
    刷题总结——doing homework again(hdu1789)
    NOIP2017赛前模拟(3):总结
  • 原文地址:https://www.cnblogs.com/pfzeng/p/4476580.html
Copyright © 2011-2022 走看看