jQuery的document ready与 onload事件——你真的思考过吗?

jQuery的document ready与 onload事件——你真的思考过吗?

在进行实验和资料查询时,我遇到了几个关键问题:javascript

1. window.onload究竟是什么加载完触发?html

2. body为何会有onload事件?java

3. 为何是window.onload,而不是document.onload?react

4. document ready究竟是什么ready,DOM渲染完成?jquery

5. jQuery怎么实现$(document).ready?ajax

6. jQuery的ready,还能ready什么?浏览器

7. jQuery的document ready就必定比window.onload快吗?缓存

8. 为何外部script文件放页面内容后面好,是必定的吗?async

onloadide

load是一个事件,会在页面包含文件资源加载完成后触发。

支持该事件的HTML标签:

body、frame、frameset、iframe、img、link、script。

这里有两点我很在乎的是:

1. 其余标签是没有该事件,因此不要胡乱用。

2. 就如我开头提的问题之一,为何body会有onload?(Question 2)

首先,我为何有这个疑问,由于能够看出的是,支持该事件的其余标签都是为了加载标签里的src资源,而body显然不是。

我在《JavaScript高级程序设计》找到一个合理的解释:

通常来讲,在window上面发生的任何事件均可以在body元素中经过相应的特性来指定,由于在HTML中没法访问window元素。这样是为了保证向后兼容的权宜之计,但全部浏览器都能很好地支持这种方式。

结论:为了对应上window.onload,body标签才有onload。

支持该事件的JavaScript对象:

p_w_picpath、window。

这里有两个问题我很在乎:

1. window.onload究竟是什么加载完触发?(Question 1)

依资料记载,当页面彻底加载后(包括全部图像、JavaScript文件等外部资源),就会触发该事件。这方式跟在body上写onload效果是同样的。

2. 为何是window.onload,而不是document.onload? (Question 3)

按上面那个问题的解释,明明是整个document里面彻底加载后触发,那为何是window.onload(在window上是什么鬼),而不是document.onload?

仍是按《JavaScript高级程序设计》上解释:

根据“DOM2级事件”规范,应该是在document而非window上面触发load事件。可是,全部浏览器都在window上面实现了该事件,以确保向后兼容。

结论:道理是这么道理,但你们都这么干了。

jQuery document ready

从原生js来说,并无ready这种事件。

那么 document ready究竟是什么ready了(Question 4)

按资料说明,这个事件指的是文档结构(DOM)加载完成触发的。

PS:这解释还算合理,就放过这问题。

那jQuery怎么实现$(document).ready(Question 5)

下面我尝试解析jquery3.0.0版本(兼容IE9+,现代浏览器)里面关于ready事件的实现!

注意:

版本我选择比较新的3.0.0,相比于较旧版本(例1.x)的,里面的实现会简单一些,由于舍弃一些兼容代码。不过实现的原理是同样,倒不须要多个版本都详看。

原理:

在jquery脚本加载的时候,会监听DOMContentLoaded事件(监听load是补救后路)。当事件触发时候,会执行ready事件的回调。

代码:

复制代码

var readyList = jQuery.Deferred(); 
//保存全部DOM加载完后执行的函数。jQuery.fn.ready = function( fn ) {
     readyList.then( fn );     return this;
};
 
jQuery.extend( { 
     //标记DOM ready事件是否触发过。
     isReady: false, 
     // A counter to track how many items to wait for before
     // the ready event fires. See #6781
     readyWait: 1, 
     // Hold (or release) the ready event
     holdReady: function( hold ) {          if ( hold ) {
               jQuery.readyWait++;
          } else {
               jQuery.ready( true );
          }
     }, 
     // Handle when the DOM is ready
     ready: function( wait ) { 
          // Abort if there are pending holds or we're already ready
          if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {               return;
          } 
          // 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 ] );
     }
} );
 
jQuery.ready.then = readyList.then; 
// The ready event handler and self cleanup methodfunction completed() {
     document.removeEventListener( "DOMContentLoaded", completed );
     window.removeEventListener( "load", completed );
     jQuery.ready();
} 
// Catch cases where $(document).ready() is called// after the browser event has already occurred.// Support: IE <=9 - 10 only// Older IE sometimes signals "interactive" too soonif ( document.readyState === "complete" ||
     ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { 
     // Handle it asynchronously to allow scripts the opportunity to delay ready     window.setTimeout( jQuery.ready );
 
} else {     // Use the handy event callback
     document.addEventListener( "DOMContentLoaded", completed ); 
     //其实最奸诈是这里,在不支持DOMContentLoaded事件的浏览器,用load事件代替
     // A fallback to window.onload, that will always work
     window.addEventListener( "load", completed );
}

复制代码

特别地方:

1. 注册事件是用addEventListener,因此该jquery版本应该是只支持IE9+。

2. jQuery的ready,还能ready什么?(Question 6)

ready函数仅能用于当前document,所以无需选择器,因此不能ready其余元素。

三种姿式使用该函数:

$(document).ready(

谁更快?

jQuery的document ready就必定比window.onload快吗?(Question 7)

我写了一个例子来实验:

复制代码

<!DOCTYPE HTML><html lang="en-US"><head><meta charset="UTF-8"/><title>加载时机</title><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"onload="console.log('jquery.js loaded')"></script><script>
     console.log('define functions');     function load(type, info){
          console.log(type + ' || ""), new Date().getTime());
     }
     $(document).ready(function () {
          load('document ready');
     });
     document.onload = function () {
          load('document');
     };    
     window.onload = function () {
          load('window');
     };
     window.addEventListener("load",function(){
          load('window addEventListener');
     });
     document.addEventListener( "DOMContentLoaded", function () {
          load('DOMContentLoaded');
     });</script></head>
     <body onload="load('body')">
          <div onload="load('text')">test</div>
          <img onload="load('img',1)" src="http://www.deskcar.com/desktop/else/2013714232149/17.jpg" />
          <img onload="load('img',2)" src="http://www.deskcar.com/desktop/else/2013714232149/16.jpg" />
          <script onload="load('js')" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.0/react.min.js"></script>
     </body></html>

复制代码

这种大致有两种结果:

首次加载:

spacer.gif二次加载:

spacer.gif第一种状况很是符合咱们的想法,ready比onload快,顺序也比较合理。

而第二种状况就有些怪异,应该依照上面jquery ready事件的实现,那ready应该要DOMContentLoaded后面啊。我思来想去,我以为这是个误会,因为二次加载时利用到缓存,致使文件资源都很快加载,各个事件触发的时间很是相近,顺序也不定,就给人一种ready顺序不对之感,你们应该发现这几个事件都是在几十毫秒以内触发。

PS:js执行须要时间,几十毫秒不一样的顺序我以为很正常。另个尝试几回,二次加载顺序确实会有变化,但时间都很相近。

因此,jQuery的document ready不必定比window.onload快执行。

为何外部script文件放页面内容后面好?

script执行顺序:

《JavaScript高级程序设计》说过——不管如何包含代码,只要不存在defer和async属性,浏览器都会按照<script>元素在页面中出现的前后顺序对它们依次进行解析。换句话说,在第一个<script>元素包含的代码解析完成后,第二个<script>包含代码才会被解析,而后才是第三个.....

放head元素里:

复制代码

<!DOCTYPE HTML><html lang="en-US"><head><meta charset="UTF-8"/><title>Example</title><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.0/react.min.js"></script></head>
     <body>
    
     </body></html>

复制代码

在head元素里包含全部JavaScript文件,就必须等到所有JavaScript代码都被下载、解析和执行完成之后,才能呈现页面的内容(浏览器在遇到<body>标签时才开始呈现内容)。在须要不少JavaScript文件时候,浏览器呈现页面会出现明显的延迟,延时期间浏览器是一片空白。

因此,外部script文件放页面内容后面。这样,在解析JavaScript代码以前,页面内容将彻底呈现出来。

必定是放页面内容后面吗?

有种状况是JavaScript放哪里都同样的,那就是内容是依赖JavaScript的执行渲染时候,放哪都同样。

 

总结

虽然这篇文章是简单的问题,但有时咱们就是连简单的东西都没搞懂,还觉得咱们懂了。


本文为原创文章,转载请保留原出处,方便溯源,若有错误地方,谢谢指正。

本文地址 :http://www.cnblogs.com/lovesong/p/5641834.html

相关文章
相关标签/搜索