前言:

ready()事件的应用,是大家再熟悉不过的了,学jQuery的第一步,最最常见的代码:

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

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

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

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

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

原因在于以下几点:

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()函数。

     if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
} /*省略*/ try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( doScrollCheck, 1 );
return;
} // and execute any waiting functions
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的源码和设计,是一个捷径。

js便签笔记(6)——jQuery中的ready()事件为何需要那么多代码?的更多相关文章

  1. js便签笔记(2)——DOM元素的特性(Attribute)和属性(Property)

    1.介绍: 上篇js便签笔记http://www.cnblogs.com/wangfupeng1988/p/3626300.html最后提到了dom元素的Attribute和Property,本文简单 ...

  2. js便签笔记(12)——浏览TOM大叔博客的学习笔记 part2

    1. 前言 昨天写了<js便签笔记(11)——浏览TOM大叔博客的学习笔记 part1>,简单记录了几个问题.part1的重点还是在于最后那个循环创建函数的问题,也就是多个子函数公用一个闭 ...

  3. js便签笔记(13)——jsonp事实上非常easy【ajax跨域请求】

    前两天被问到ajax跨域怎样解决,还真被问住了,光知道有个什么jsonp,迷迷糊糊的没有说上来.抱着有问题必须解决的态度,我看了很多资料,原来如此.. . 为何一直知道jsonp,但一直迷迷糊糊的不明 ...

  4. js便签笔记(9)——解读jquery源码时记录的一些知识点

    近来一直利用业余时间在看jquery2.1.1源码,大约看了两千行了.平时看的时候,做了一些笔记,贴出来分享. 1. Array.prototype.slice.call 可以将伪数组转化为真正的数组 ...

  5. js便签笔记(5)——Dean Edwards大牛的跨浏览器AddEvent()设计(不知道是不是jQuery事件系统的原型)

    1. 前言: 在看Aaron的jquery源码解读时候,看到事件系统那块,作者提到了Dean Edwards的添加事件的设计,于是就点进去看了看.首先让我吃惊的是,代码非常少,寥寥几十行,非常简单.于 ...

  6. js便签笔记(13)——jsonp其实很简单【ajax跨域请求】

    前两天被问到ajax跨域如何解决,还真被问住了,光知道有个什么jsonp,迷迷糊糊的没有说上来.抱着有问题必须解决的态度,我看了许多资料,原来如此... 为何一直知道jsonp,但一直迷迷糊糊的不明白 ...

  7. js便签笔记(11)——浏览TOM大叔博客的学习笔记 part1

    1. 前言 这两天看了一下TOM大叔的<深入理解js系列>中的基础部分,根据自己的实际情况,做了读书笔记,记录了部分容易绊脚的问题.写篇文章,供大家分享. 2. 关于HTMLCollect ...

  8. js便签笔记(10) - 分享:json2.js源码解读笔记

    1. 如何理解“json” 首先应该意识到,json是一种数据转换格式,既然是个“格式”,就是个抽象的东西.它不是js对象,也不是字符串,它只是一种格式,一种规定而已. 这个格式规定了如何将js对象转 ...

  9. js便签笔记(10) - 分享:json.js源码解读笔记

    1. 如何理解“json” 首先应该意识到,json是一种数据转换格式,既然是个“格式”,就是个抽象的东西.它不是js对象,也不是字符串,它只是一种格式,一种规定而已. 这个格式规定了如何将js对象转 ...

随机推荐

  1. Ng第十课:应用机器学习的建议(Advice for Applying Machine Learning)

    10.1  决定下一步做什么 10.2  评估一个假设 10.3  模型选择和交叉验证集 10.4  诊断偏差和方差 10.5  归一化和偏差/方差 10.6  学习曲线 10.7  决定下一步做什么 ...

  2. 线段树区间覆盖 蛤玮打扫教室(zzuli 1877)

    http://acm.zzuli.edu.cn/zzuliacm/problem.php?id=1877 Description   现在知道一共有n个机房,算上蛤玮一共有m个队员,教练做了m个签,每 ...

  3. Flink的入门

    Apache Flink(下简称Flink)项目是大数据处理领域最近冉冉升起的一颗新星,其不同于其他大数据项目的诸多特性吸引了越来越多人的关注.本文将深入分析Flink的一些关键技术与特性,希望能够帮 ...

  4. Hadoop-1.2.1伪分布下 hive-0.10.0内嵌模式安装

    Hadoop-1.2.1伪分布下 hive-0.10.0内嵌模式安装 1.下载hive-0.10.0 网址是:http://archive.apache.org/dist/hive/hive-0.10 ...

  5. 学习stm32 让我们一起回顾一下C语言吧

    ODR 是一个端口输出数据寄存器,也只用了低 16 位.该寄存器为可读写,从该寄存器读出来的数据可以用于判断当前 IO 口的输出状态.而向该寄存器写数据,则可以控制某个 IO 口的输出电平.该寄存器的 ...

  6. shell 命令 --ps aux | grep

    ps aux | grep  要查询的进程名 查询当前进程,如 ps aux | grep python 确认过需要查询的进程,就可以进行 kill -9 进程号等操作了.

  7. 11.Scrapy登录

    Request Request 部分源码: # 部分代码 class Request(object_ref): def __init__(self, url, callback=None, metho ...

  8. 分形之希尔伯特-皮亚诺(Hilbert-Peano)曲线

    1890年,意大利数学家皮亚诺(Peano G)发明能填满一个正方形的曲线,叫做皮亚诺曲线.后来,由希尔伯特作出了这条曲线,又名希尔伯特曲线.Hilbert-Peano曲线是一种分形图形,它可以画得无 ...

  9. MySql and Oracle Data Type Mappings

    the default settings used by SQL Developer to convert data types from MySQL to Oracle. SQL Developer ...

  10. Constructor in depth

    There are two types of constructor:Instance Constructor and Type Constructor(or so-called Static Con ...