很早以前就留下了這個問題,遇上五一放假,好好研究總結一下吧。javascript
首先jq中ready方法和window的onload方法的不一樣這裏再提一下,首先ready只是dom樹加載完畢,一些img等資源可能還沒加載完成,而onload則是所有加載成功。並且ready方法能夠有多個,而onload只能寫一個。還有一個區別是什麼了,想起來補上。java
通常讓咱們手寫模擬一個jq的ready方法,我大多都是這樣寫:web
document.ready = function (callback) { ///兼容FF,Google if (document.addEventListener) { document.addEventListener('DOMContentLoaded', function () { document.removeEventListener('DOMContentLoaded', arguments.callee, false); callback(); }, false) } //兼容IE else if (document.attachEvent) { document.attachEvent('onreadystatechange', function () { if (document.readyState == "complete") { document.detachEvent("onreadystatechange", arguments.callee); callback(); } }) } else if (document.lastChild == document.body) { callback(); } }
先檢測DOMContentLoaded事件,而後撤銷綁定,在觸發回調,IE的就是檢測onreadystatechange事件,若是document.readyState == "complete"就老樣子先撤銷綁定事件,最後觸發回調,最後就是一個退化操做。瀏覽器
ready方法出現的緣由就是window.onload事件是在頁面全部的資源都加載完畢後觸發的. 若是頁面上有大圖片等資源響應緩慢, 會致使window.onload事件遲遲沒法觸發.因此出現了DOM Ready事件. 此事件在DOM文檔結構準備完畢後觸發, 即在資源加載前觸發.dom
通常在主流瀏覽器,DOMContentLoaded 事件在許多Webkit瀏覽器以及IE9上均可以使用, 此事件會在DOM文檔準備好之後觸發, 包含在HTML5標準中. 對於支持此事件的瀏覽器, 直接使用DOMContentLoaded事件是最簡單最好的選擇.可是IE6,7,8都不支持DOMContentLoaded事件。異步
在上面代碼中也就是這樣寫的,第一檢測的仍是DOMContentLoaded事件,並且老版本瀏覽器或者IE6-8中,hack的方法就不知一種了:async
//onreadystatechange event document.onreadystatechange = function(e){ document.getElementById("divMsg").innerHTML += "<br/> onreadystatechange, readyState:" + document.readyState; };
//doScroll var doScrollMoniterId = null; var doScrollMoniter = function(){ try{ document.documentElement.doScroll("left"); document.getElementById("divMsg").innerHTML += "<br/>doScroll, readyState:" + document.readyState; if(doScrollMoniterId){ clearInterval(doScrollMoniterId); } } catch(ex){ } } doScrollMoniterId = setInterval(doScrollMoniter, 1);
var setTimeoutReady = function(){ document.getElementById("divMsg").innerHTML += "<br/> setTimeout , readyState:" + document.readyState; }; var setTimeoutBindReady = function(){ /in/.test(document.readyState)?setTimeout(arguments.callee, 1):setTimeoutReady(); }; setTimeoutBindReady();
上面的一些方法其實也存在問題,好比readyState狀態爲complete的時候圖片已經加載完了。
因此引自一個大佬的說法就是:
函數
具體使用doScroll的話上次看到了這種寫法:code
//爲了保證最後必定會調用ready方法,在上面每一種方式的最後都仍是會爲load事件綁定ready方法。 if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready //這裏的setTimeout是爲了異步 setTimeout( jQuery.ready, 1 ); // Standards-based browsers support DOMContentLoaded //標準瀏覽器偵聽事件接口:document.addEventListener } else if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); // A fallback to window.onload, that will always work //文章一開始說了,這裏爲了保證必定會觸發ready,因此還針對onload也綁定一次回調 window.addEventListener( "load", jQuery.ready, false ); // If IE event model is used } else { //IE偵聽事件接口:document.attachEvent //若是有onreadystatechange事件,偵聽之 // 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 ); // http://javascript.nwbox.com/IEContentLoaded/ // 見下邊說明 // 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) {} //若是是IE而且不是iframe if ( top && top.doScroll ) { (function doScrollCheck() { if ( !jQuery.isReady ) { try { // Use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ //一直調用doScroll滾動,由於DOM渲染結束前,DOM節點是沒有doScroll方法的,因此一直會異常 //直到DOM渲染結束了,這個時候doScroll方法不會拋出異常,而後就調用$.ready() top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // and execute any waiting functions jQuery.ready(); } })(); } }
上面的代碼即實現這樣的流程:
blog
jQuery源碼的實現稍有複雜,等往後分析懂了繼續補充。