zoukankan      html  css  js  c++  java
  • jQuery之ready源码分析

    只要使用过jQuery的,想必对ready都不陌生,$(function(){})和$(document).ready(function(){})的使用更是习以为常。

    要说到window.onload与document.ready的区别也能谈出个一二,最重要的区别就是:

    window.onload是在dom文档树以及所有文件都加载完成后,才执行;

    而document.ready是,只要dom文档树加载完,就执行,且当dom文档树加载完就执行的好处就是,当页面中的图片等外部资源过多时,window.onload迟迟不能触发,这时若还没有绑定事件,用户点击按钮时没有反应,这不影响用户体验么。

    咦,Jquery的ready这么牛逼,那Jquery是怎么实现ready这个函数的呢?我们不妨一起来探究探究。

    以下Jquery.ready的源码,截自于jQuery 1.12.0

     1 jQuery.ready.promise = function( obj ) {
     2     if ( !readyList ) {
     3 
     4         readyList = jQuery.Deferred();
     5 
     6         // Catch cases where $(document).ready() is called
     7         // after the browser event has already occurred.
     8         // we once tried to use readyState "interactive" here,
     9         // but it caused issues like the one
    10         // discovered by ChrisS here:
    11         // http://bugs.jquery.com/ticket/12282#comment:15
    12         if ( document.readyState === "complete" ) {
    13 
    14             // Handle it asynchronously to allow scripts the opportunity to delay ready
    15             window.setTimeout( jQuery.ready );
    16 
    17         // Standards-based browsers support DOMContentLoaded
    18         } else if ( document.addEventListener ) {
    19 
    20             // Use the handy event callback
    21             document.addEventListener( "DOMContentLoaded", completed );
    22 
    23             // A fallback to window.onload, that will always work
    24             window.addEventListener( "load", completed );
    25 
    26         // If IE event model is used
    27         } else {
    28 
    29             // Ensure firing before onload, maybe late but safe also for iframes
    30             document.attachEvent( "onreadystatechange", completed );
    31 
    32             // A fallback to window.onload, that will always work
    33             window.attachEvent( "onload", completed );
    34 
    35             // If IE and not a frame
    36             // continually check to see if the document is ready
    37             var top = false;
    38 
    39             try {
    40                 top = window.frameElement == null && document.documentElement;
    41             } catch ( e ) {}
    42 
    43             if ( top && top.doScroll ) {
    44                 ( function doScrollCheck() {
    45                     if ( !jQuery.isReady ) {
    46 
    47                         try {
    48 
    49                             // Use the trick by Diego Perini
    50                             // http://javascript.nwbox.com/IEContentLoaded/
    51                             top.doScroll( "left" );
    52                         } catch ( e ) {
    53                             return window.setTimeout( doScrollCheck, 50 );
    54                         }
    55 
    56                         // detach all dom ready events
    57                         detach();
    58 
    59                         // and execute any waiting functions
    60                         jQuery.ready();
    61                     }
    62                 } )();
    63             }
    64         }
    65     }
    66     return readyList.promise( obj );
    67 };

    从上面的源码中,可以看出,jQuery.ready主要通过以下几个东东来判断dom文档树是否加载完成:

    (1)  document.readyState

    (2)  DOMContentLoaded

    (3)  onreadystatechange

    (4)  doScroll

    下面,我们就一步一步来解析

    1、  document.readyState

    readyState是个什么东东呢?它是document的一个属性值,返回当前文档的状态,该属性会根据文档加载情况,返回如下几个属性值:

    属性值

    意义

    uninitialized

    还未开始载入

    loading

    载入中

    interactive

    已加载,文档与用户可以开始交互

    complete

    载入完成

    从属性值,可得知,倘若当我们判断document.readyState为complete,那么DOM文档树就是加载完毕。但,从上面源码注释(6--11行)中可以得知ChrisS发现了一个很特别的问题,所以我们在判断document.readyState === ‘complete’后,执行jQuery.ready,需要延迟一下。但上面的代码中,怎么没有延迟时间呢?

    那是因为倘若我们没有设置延迟时间,setTimeout就会根据当前浏览器及操作系统,自动给它设定一个最小延迟时间。在《JavaScript忍者的秘密》中曾提到:

     

    2、  DOMContentLoaded事件

    从上面的源代码注释中,可以看出DOMContentLoaded是基于标准的浏览器的。

    那么它的作用是什么呢?

    当DOM文档树加载完成后,即触发。

    所以可以在标准的浏览器中判断DOMContentLoaded,来判断DOM树,是否加载完成。

    3、  onreadystatechange事件

    上面的DOMContentLoaded事件是基于标准的浏览器的,那倘若不标准的呢,如IE,则使用onreadystatechange事件。

    咦,怎么感觉如此熟悉。

    XMLHttpRequest—>Ajax。想起来了么。在IE中onreadystatechange是私有化的,即所有元素都存在onreadystatechange事件,而W3C标准中,仅XMLHttpRequest对象中存在onreadystatechange事件。所以当事件触发时,倘若onreadystatechange === complete,则可视为DOM树加载完成。

    4、  doScroll

    从上面的源码中的注释(49--50行),可得,Diego Perini报告一种检测IE下DOM文档是否加载完成的方法,即,使用doScroll。

    咦,上面onreadystatechange事件,不是能处理了吗?!!

    是的,但是它有个弊端,就是当页面中存在图片时,可能反而会晚于onload事件后,触发。

    为什么呢?

    因为我们是依据onreadystatechange === complete来判断的嘛,如果图片没加载或者正在加载中,那么onreadystatechange就不等于complete了哦。

    所以为了保险起见,再用doScroll来检测。

    doScroll的原理就是,当页面DOM未加载完成时,调用doScroll方法,会产生异常。所以利用try-catch来对doScroll捕获异常就可以判断DOM文档是否加载完咯。

    好了,jQuery.ready的源码就解析到这儿,纯属自己观点,有什么不对,请狠狠拍砖且交流,谢谢。

  • 相关阅读:
    一个文件汇集搜索系统(NiFi + ELK)
    Apache NiFi
    JSONPath
    git免密push方法
    SSH的那些keys
    Elasticsearch
    kubernetes intro
    几个流行的npm包
    Micro-Frontend微前端
    Consul服务注册与服务发现
  • 原文地址:https://www.cnblogs.com/giggle/p/5246798.html
Copyright © 2011-2022 走看看