在進行實驗和資料查詢時,我遇到了幾個關鍵問題: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>
這種大致有兩種結果:
首次加載:
二次加載:
第一種狀況很是符合咱們的想法,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的執行渲染時候,放哪都同樣。
總結
雖然這篇文章是簡單的問題,但有時咱們就是連簡單的東西都沒搞懂,還覺得咱們懂了。
本文爲原創文章,轉載請保留原出處,方便溯源,若有錯誤地方,謝謝指正。