很早以前就留下了这个问题,遇上五一放假,好好研究总结一下吧。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源码的实现稍有复杂,等往后分析懂了继续补充。