JavaScript的jQuery库中ready方法的学习教程

学习 jQuery 有许多途径,我们今天从 jQuery 的 ready 函数开始。本例中的代码都来自于 jQuery 脚本库。

如果你使用过 jQuery , 就必然使用过 ready 函数,它用来注册当页面准备好之后可以执行的函数。

问题来啦,我们的页面什么时候准备好了呢?

onload 事件
最基本的处理方式就是页面的 onload 事件,我们在处理这个事件的时候,可以有多种方式,即可以通过 HTML 方式,直接写在 body 元素的开始标记中,也可以使用事件注册的方式来使用,这又可以分为 DOM0 方式和 DOM2 方式。再考虑到浏览器的兼容性,使用 DOM2 方式写出来,如下所示。

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

  // If IE event model is used
} else {
  // A fallback to window.onload, that will always work
  window.attachEvent("onload", jQuery.ready);
}

DOMContentLoaded 事件
不过 onload 事件要等到所有页面元素加载完成才会触发, 包括页面上的图片等等。如果网页上有大量的图片,效果可想而知,用户可能在没有看到图片的时候,就已经开始操作页面了,而这时我们的页面还没有初始化,事件还没有注册上,这岂不是太晚了!

除了大家熟知的 onload 事件之外, 与 DOM 中的 onload 事件相近的,我们还有 DOMContentLoaded 事件可以考虑, 基于标准的浏览器支持这个事件,  当所有 DOM 解析完以后会触发这个事件。

这样,对于基于标准的浏览器来说,我们还可以注册这个事件的处理。这样,我们可能更早地捕获到加载完成的事件。

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);
}

onreadystatechange 事件
不标准的浏览器怎么办呢?

如果浏览器存在 document.onreadystatechange 事件,当该事件触发时,如果 document.readyState=complete 的时候,可视为 DOM 树已经载入。

不过,这个事件不太可靠,比如当页面中存在图片的时候,可能反而在 onload 事件之后才能触发,换言之,它只能正确地执行于页面不包含二进制资源或非常少或者被缓存时作为一个备选吧。

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);

  // If IE event model is used
} else {
  // Ensure firing before onload, maybe late but safe also for iframes
  document.attachEvent("onreadystatechange", DOMContentLoaded);

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

DOMContentLoaded 函数在做什么呢?最终还是要调用 jQuery.ready 函数。

DOMContentLoaded = function() {
  if ( document.addEventListener ) {
    document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
    jQuery.ready();
  } else if ( document.readyState === "complete" ) {
    // we're here because readyState === "complete" in oldIE
    // which is good enough for us to call the dom ready!
    document.detachEvent( "onreadystatechange", DOMContentLoaded );
    jQuery.ready();
  }
}

doScroll 检测法
MSDN 关于 JScript 的一个方法有段不起眼的话,当页面 DOM 未加载完成时,调用 doScroll 方法时,会产生异常。那么我们反过来用,如果不异常,那么就是页面DOM加载完毕了!

Diego Perini 在 2007 年的时候,报告了一种检测 IE 是否加载完成的方式,使用 doScroll 方法调用。详细的说明见这里。
原理是对于 IE 在非 iframe 内时,只有不断地通过能否执行 doScroll 判断 DOM 是否加载完毕。在本例中每间隔 50 毫秒尝试去执行 doScroll,注意,由于页面没有加载完成的时候,调用 doScroll 会导致异常,所以使用了 try -catch 来捕获异常。

(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);
    }

    // and execute any waiting functions
    jQuery.ready();
  }
})();

document.readyState 状态
如果我们注册 ready 函数的时间点太晚了,页面已经加载完成之后,我们才注册自己的 ready 函数,那就用不着上面的层层检查了,直接看看当前页面的 readyState 就可以了,如果已经是 complete ,那就可以直接执行我们准备注册的 ready 函数了。不过 ChrisS 报告了一个很特别的错误情况,我们需要延迟一下执行。

setTimeout 经常被用来做网页上的定时器,允许为它指定一个毫秒数作为间隔执行的时间。当被启动的程序需要在非常短的时间内运行,我们就会给她指定一个很小的时间数,或者需要马上执行的话,我们甚至把这个毫秒数设置为0,但事实上,setTimeout有一个最小执行时间,当指定的时间小于该时间时,浏览器会用最小允许的时间作为setTimeout的时间间隔,也就是说即使我们把setTimeout的毫秒数设置为0,被调用的程序也没有马上启动。

这个最小的时间间隔是多少呢?这和浏览器及操作系统有关。在John Resig的新书《Javascript忍者的秘密》一书中提到

Browsers all have a 10ms minimum delay on OSX and a(approximately) 15ms delay on Windows.(在苹果机上的最小时间间隔是10毫秒,在Windows系统上的最小时间间隔大约是15毫秒)

,另外,MDC中关于setTimeout的介绍中也提到,Firefox中定义的最小时间间隔(DOM_MIN_TIMEOUT_VALUE)是10毫秒,HTML5定义的最小时间间隔是4毫秒。既然规范都是这样写的,那看来使用setTimeout是没办法再把这个最小时间间隔缩短了。

这样,通过设置为 1, 我们可以让程序在浏览器支持的最小时间间隔之后执行了。

// 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") {
  // 延迟 1 毫秒之后,执行 ready 函数
  setTimeout(jQuery.ready, 1);
}

完整的代码
在 jQuery 中完整的代码如下所示。位于 jQuery 1.8.3 源代码的 #842 行。

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, 1 );

    // Standards-based browsers support DOMContentLoaded
    } else 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 );

    // If IE event model is used
    } else {
      // Ensure firing before onload, maybe late but safe also for iframes
      document.attachEvent( "onreadystatechange", DOMContentLoaded );

      // A fallback to window.onload, that will always work
      window.attachEvent( "onload", jQuery.ready );

      // 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 );
            }

            // and execute any waiting functions
            jQuery.ready();
          }
        })();
      }
    }
  }
  return readyList.promise( obj );
};

那么,又是谁来调用呢?当然是需要的时候,在我们调用 ready 函数的时候,才需要注册这些判断页面是否完全加载的处理,这段代码在 1.8.3 中位于代码的 #244 行,如下所示:

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

  return this;
}

在页面上引用 jQuery 脚本库之后,执行了 jQuery 的初始化函数,初始化函数中创建了 ready 函数。我们在通过 ready 函数注册事件处理之前,jQuery 完成了页面检测代码的注册。这样。当页面完全加载之后,我们注册的函数就被调用了。

jQuery Ready 方法的简短写法

写 jQuery 代码的时候,一般要写一个 Ready 方法,以确保 DOM 已加载完毕,然后再执行相应的 jQuery 代码。Ready 方法一般写法如下:

$(document).ready(function() {
  // 从这里开始
});

但是在看其他人写的 jQuery 代码的时候,经常又会看到如下写法:

$(function() {
  // 从这里开始
});

第二种写法虽然简短了许多,但是在功能上和第一种写法是等价的,如果你不相信,可以看一下 jQuery 的源代码中有如下代码片段:

// HANDLE: $(function)
// Shortcut for document ready
if ( jQuery.isFunction( selector ) ) {
  return rootjQuery.ready( selector );
}

如果传入选择器中的参数是一个函数,那么会自动返回一个 rootjQuery.ready( selector ),而 rootjQuery 又是 jQuery(document) 的一个引用,所以这里就相当于调用 jQuery(document).ready() 方法,而之前的那个匿名方法亦被传入其中以备执行。

这种简短写法虽说减少了了一点代码量,但是可读性稍差,所以我个人还是倾向于前面的第一种写法,特别是在团队开发中,仅仅是为了语意明确。

(0)

相关推荐

  • JQuery的read函数与js的onload不同方式实现

    js的onload实现: 复制代码 代码如下: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Con

  • jQuery之$(document).ready()使用介绍

    学习jQuery的第一件事是:如果你想要一个事件运行在你的页面上,你必须在$(document).ready()里调用这个事件.所有包括在$(document).ready()里面的元素或事件都将会在DOM完成加载之后立即加载,并且在页面内容加载之前. If you want an event to work on your page, you should call it inside the $(document).ready() function. Everything inside it

  • 模拟jQuery中的ready方法及实现按需加载css,js实例代码

    一.ready函数的实现经常用jQuery类库或其他类库中的ready方法,有时候想想它们到底是怎么实现的,但是看了一下jQuery中的源码,涉及到的模块比较多,(水平有限)代码比较难看懂:自己结合了一些书籍内容,总结一下.先说一下ready函数的实现思路:变量ready通过表达式赋值,右侧为一个自执行匿名函数,在这个匿名函数中,首先为各个浏览器的事件绑定处理函数,并为isReady赋值(根据事件异步处理程序来确定),然后返回一个传参闭包,在闭包中,主要判断isReady值来执行操作,如果dom

  • 用javascript实现jquery的document.ready功能的实现代码

    实现jQuery的document.ready功能 document.ready (function () { var ie = !!(window.attachEvent && !window.opera); var wk = /webkit\/(\d+)/i.test(navigator.userAgent) && (RegExp.$1 1) return; if (ie) (function () { try { d.documentElement.doScroll(

  • jQuery的Read()方法代替原生JS详解

    在jQuery 3.0的版本前, ready经典用法是用一个匿名函数,像这样: $(document).ready(function() { // Handler for .ready() called. }); jQuery 3.0 ready() 变化 在jQuery 3.0发布之前,有以下几种方法称之为ready方法: 在document元素上操作: $(document).ready(handler); 在空元素上操作: $().ready(handler); 或者直接(即不在一个具体的

  • jquery $(document).ready() 与window.onload的区别

    1.执行时间 window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行.         $(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕. 2.编写个数不同 window.onload不能同时编写多个,如果有多个window.onload方法,只会执行一个          $(document).ready()可以同时编写多个,并且都可以得到执行 3.简化写法 window.onload没有简化写法          $(documen

  • 全面解析jQuery $(document).ready()和JavaScript onload事件

    对元素的操作和事件的绑定需要等待一个合适的时机,可以看下面的例子: <!DOCTYPE html> <meta charset="utf-8"> <html> <head> <title>1-1</title> <script type="text/javascript"> document.getElementById("panel").onclick = fu

  • JQuery的ready函数与JS的onload的区别详解

    JQuery的ready函数与JS的onload的区别:1.执行时间window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行.$(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕. 2.编写个数不同window.onload不能同时编写多个,如果有多个window.onload方法,只会执行一个$(document).ready()可以同时编写多个,并且都可以得到执行 3.简化写法window.onload没有简化写法$(document).r

  • jQuery中的read和JavaScript中的onload函数的区别

    在JavaScript中,onload函数是最经常使用的,几乎涉及到JavaScript的童鞋都少不了要接触它.这个函数的作用就是等待网页完全装载完了以后再去执行代码块内的语句,因为按照文档流的执行顺序,通常用于头部加载JavaScript的时候需要用到. 复制代码 代码如下: window.onload = function(){     // 当网页加载完成后执行这里的代码块 }; 而在jQuery中也有一个对应的函数,即等待网页加载完后执行代码块 复制代码 代码如下: $(document

  • javascript 模拟JQuery的Ready方法实现并出现的问题

    dom加载完后执行,一直不了解,基于对网上的一些方法逻辑不了解,所以去看了<jquery源代码研究(ready函数) >这篇文章后自己写入如下代码(已有详细说明) 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html

随机推荐