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

相關文章
相關標籤/搜索