js便签笔记(6)——jQuery中的ready()事件为什么须要那么多代码?

前言:

ready()事件的应用,是你们再熟悉不过的了,学jQuery的第一步,最最多见的代码:javascript

jQuery(document).ready(function () { });
jQuery(function () { });
$(document).ready(function () { });
$(function () { });

以上四行代码的目的和效果都同样——待DOM加载完成以后,执行传入的function函数。html

再对jquery稍微熟悉一点的朋友可能知道,这里的“待DOM加载完成”,不是window.onload事件,window.onload是指“DOM加载完成 + DOM相关的文件下载完成”。这里的“DOM加载完成”,不包括“DOM相关的文件加载完成”。相关的事件是:java

  • DOMContentLoaded事件(IE9+以及其余浏览器)
  • onreadystatechange事件(IE9如下浏览器)

问题就在这里。若是知道了这两个事件,那么把传入的function函数关联到这两个事件上就好了,而jquery中与ready相关的代码洋洋洒洒的写了那么多,至于上百行代码。这是为什么?jquery

缘由在于如下几点:web

 

2. 存储结构——基于异步队列设计:

先看如下代码:浏览器

        //应用ready事件
        $(function () {
            alert(10);
        });
        $(function () {
            alert(20);
        });
        $(function () {
            alert(30);
        });

以上代码连续应用了三次ready方法,其实jquery是用自己的jquery.callbacks来处理的。主要代码以下:异步

readyList = jQuery.Callbacks( "once memory" );
readyList.add( fn );
readyList.fireWith( document, [ jQuery ] );

"once":表明add进来的函数只被调用一次;函数

"memory":表明一旦readylist被执行过一次,那么它后续添加进来的函数会当即按照执行时候的环境和参数执行。工具

 

3. 巧妙的事件绑定:

以IE9+和其余浏览器支持的DOMContentLoaded为例。先看代码:学习

        // Mozilla, Opera and webkit nightlies currently support this event
        if ( document.addEventListener ) {
            // Use the handy event callback
            document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

            // A fallback to window.onload, that will always work
            window.addEventListener( "load", jQuery.ready, false );
        }

   DOMContentLoaded
= function() { document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); jQuery.ready(); };

根据以上代码可见,最终DOMContented事件执行的,实际上是jQUery.ready()这个工具函数。(注意,jquery.ready()和jquery(document).raedy()不同!!,前者是工具函数,后者是实例函数。)

这里是经过定义一个DOMContentLoaded函数做为桥梁来执行jquery.ready()函数的,这样作的目的就是为了即便的remove掉document的DOMContentLoaded事件的引用。

document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );

单独把这两行摘出来,能够看明白,add完了以后,接着remove掉了,在这中间,巧妙的执行了jquery.ready(),这种用法值得学习!

反过来,若是像如下代码那么样实现,document的DOMContentLoaded事件的引用将没法及时删除。

//反例
document.removeEventListener( "DOMContentLoaded", jQuery.ready, false );

 

 

另外,除了经过浏览器的DOMContentLoaded/onreadystatechange方法能够调用jquery.ready()函数以外,还有一种巧妙的方式调用jquery.ready()函数。

在IE9如下的浏览器中,若是当前页面是顶层(即没有包含在iframe和friame元素中),调用html.doScroll(),直到不抛出异常,便可调用jquery.ready()函数。

 1     if ( document.documentElement.doScroll && toplevel ) {
 2                 doScrollCheck();
 3             }
 4             
 5     /*省略*/
 6     
 7     try {
 8         // If IE is used, use the trick by Diego Perini
 9         // http://javascript.nwbox.com/IEContentLoaded/
10         document.documentElement.doScroll("left");
11     } catch(e) {
12         setTimeout( doScrollCheck, 1 );
13         return;
14     }
15 
16     // and execute any waiting functions
17     jQuery.ready();

 

4. 事件执行:

上文中讲到,能够经过浏览器的DOMContentLoaded/onreadystatechange事件,以及对html.doScroll()的检测来调用jquery.ready()工具函数,jquery.ready()最终将会调用异步队列的firewith()方法触发传入的全部事件。若是是经过js手动调用,也能够经过jquery事件系统来调用。

readyList.fireWith( document, [ jQuery ] );

if ( jQuery.fn.trigger ) {
                jQuery( document ).trigger( "ready" ).off( "ready" );
            }

 

其实这其中还有个jquery.holdready()方法用来延迟调用,不过比较简单,也不经常使用,此处不说了。

 

5. 总结:

可见,jQuery中的ready()事件并非咱们看起来那么简单,了解其原理的同时,也应该想一想咱们在本身设计系统的时候,考虑的时候全面。

  • 它用到了异步队列,使得使用者能够屡次调用,顺序执行;
  • 它的事件绑定考虑到了各类状况,而又充分考虑了资源的释放;
  • 它同时考虑了浏览器调用的状况,和js手动调用的状况。

我的感觉:想了解js到底该怎么用,了解js的源码和设计,是一个捷径。

相关文章
相关标签/搜索