假如你对$(document).ready()
的明白也仅限于在DOM Tree绘制终了后触发,那末,你也应当好好研讨下ready
的事情道理,因为,TST的面试官问过我这个题目。。。
一、关于jQuery
jQuery
是一个巨大的剧本库,由John Resig在 2006年1月的BarCamp NYC上释出第一个版本。你能够在 http://jquery.com/ 下载到最新版本。这里以jQuery1.8.3为例剖析。
进修jQuery
有很多门路,我们本日从jQuery
的ready
函数最先。本例中的代码都来自于jQuery
剧本库。
假如你运用过jQuery
,就必定运用过ready
函数,它用来注册当页面预备好以后能够实行的函数。
题目来啦,我们的页面什么时刻预备好了呢?
二、onload事宜
最基本的处置惩罚体式格局就是页面的onload
事宜,我们在处置惩罚这个事宜的时刻,能够有多种体式格局,即能够经由过程HTML
体式格局,直接写在body
元素的最先标记中,也能够运用事宜注册的体式格局来运用,这又能够分为DOM0
体式格局和DOM2
体式格局。再斟酌到浏览器的兼容性,运用DOM2
体式格局写出来,以下所示。
if (document.addEventListener) {
// A fallback to window.onload, that will always work
window.addEventListener("load", jQuery.ready, false);
// If IE event model is used
} else {
// A fallback to window.onload, that will always work
window.attachEvent("onload", jQuery.ready);
}
三、DOMContentLoaded事宜
不过onload
事宜要比及一切页面元素加载完成才会触发,包括页面上的图片等等。假如网页上有大批的图片,结果可想而知,用户能够在没有看到图片的时刻,就已最先操纵页面了,而这时候我们的页面还没有初始化,事宜还没有注册上,这岂不是太晚了!
除了人人熟知的onload
事宜以外, 与DOM
中的onload
事宜邻近的,我们另有 DOMContentLoaded
事宜能够斟酌, 基于范例的浏览器支撑这个事宜, 当一切DOM
剖析完以后会触发这个事宜。
如许,关于基于范例的浏览器来讲,我们还能够注册这个事宜的处置惩罚。如许,我们能够更早地捕捉到加载完成的事宜。
if (document.addEventListener) {
// Use the handy event callback
document.addEventListener("DOMContentLoaded", DOMContentLoaded, false);
// A fallback to window.onload, that will always work
window.addEventListener("load", jQuery.ready, false);
}
四、onreadystatechange事宜
不范例的浏览器怎么办呢?
假如浏览器存在 document.onreadystatechange
事宜,当该事宜触发时,假如 document.readyState=complete
的时刻,可视为 DOM
树已载入。
不过,这个事宜不太牢靠,比方当页面中存在图片的时刻,能够反而在 onload
事宜以后才触发,换言之,它只能正确地实行于页面不包括二进制资本或非常少或许被缓存时作为一个备选吧。
if (document.addEventListener) {
// Use the handy event callback
document.addEventListener("DOMContentLoaded", DOMContentLoaded, false);
// A fallback to window.onload, that will always work
window.addEventListener("load", jQuery.ready, false);
// If IE event model is used
} else {
// 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);
}
DOMContentLoaded
函数在做什么呢?终究照样要挪用 jQuery.ready
函数。
DOMContentLoaded = function() {
if ( document.addEventListener ) {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
jQuery.ready();
} else if ( document.readyState === "complete" ) {
// we're here because readyState === "complete" in oldIE
// which is good enough for us to call the dom ready!
document.detachEvent( "onreadystatechange", DOMContentLoaded );
jQuery.ready();
}
}
五、doScroll检测法
MSDN
关于 JScript
的一个要领有段不起眼的话,当页面 DOM
未加载完成时,挪用 doScroll
要领时,会发生非常。那末我们反过来用,假如不非常,那末就是页面DOM
加载终了了!
Diego Perini 在 2007 年的时刻,报告了一种检测 IE
是不是加载完成的体式格局,运用 doScroll
要领挪用。细致的申明见这里。
道理是关于 IE
在非 iframe
内时,只要不断地经由过程可否实行 doScroll
推断 DOM
是不是加载终了。在本例中每距离 50 毫秒尝试去实行 doScroll
,注重,因为页面没有加载完成的时刻,挪用 doScroll
会致使非常,所以运用了 try -catch
来捕捉非常。
(function doScrollCheck() {
if (!jQuery.isReady) {
try {
// Use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
top.doScroll("left");
} catch (e) {
return setTimeout(doScrollCheck, 50);
}
// and execute any waiting functions
jQuery.ready();
}
})();
六、document.readyState状况
假如我们注册 ready
函数的时候点太晚了,页面已加载完成以后,我们才注册本身的 ready
函数,那就用不着上面的层层搜检了,直接看看当前页面的 readyState
就能够了,假如已是 complete
,那就能够直接实行我们预备注册的 ready
函数了。不过 ChrisS 报告了一个很迥殊的毛病状况,我们须要耽误一下实行。
setTimeout
经常被用来做网页上的定时器,许可为它指定一个毫秒数作为距离实行的时候。当被启动的顺序须要在非常短的时候内运转,我们就会给她指定一个很小的时候数,或许须要立时实行的话,我们以至把这个毫秒数设置为0,但事实上,setTimeout
有一个最小实行时候,当指定的时候小于该时候时,浏览器会用最小许可的时候作为setTimeout
的时候距离,也就是说纵然我们把setTimeout
的毫秒数设置为0,被挪用的顺序也没有立时启动。
这个最小的时候距离是多少呢?这和浏览器及操纵体系有关。在John Resig的新书《Javascript忍者的隐秘》一书中提到
Browsers all have a 10ms minimum delay on OSX and a(approximately) 15ms delay on Windows.(在苹果机上的最小时候距离是10毫秒,在Windows体系上的最小时候距离大约是15毫秒)
别的,MDC
中关于setTimeout
的引见中也提到,Firefox
中定义的最小时候距离(DOM_MIN_TIMEOUT_VALUE)是10毫秒,HTML5定义的最小时候距离是4毫秒。既然范例都是如许写的,那看来运用setTimeout
是没办法再把这个最小时候距离缩短了。
如许,经由过程设置为 1, 我们能够让顺序在浏览器支撑的最小时候距离以后实行了。
// Catch cases where $(document).ready() is called after the browser event has already occurred.
// we once tried to use readyState "interactive" here, but it caused issues like the one
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
if (document.readyState === "complete") {
// 耽误 1 毫秒以后,实行 ready 函数
setTimeout(jQuery.ready, 1);
}
七、完整代码
jQuery.ready.promise = function( obj ) {
if ( !readyList ) {
readyList = jQuery.Deferred();
// Catch cases where $(document).ready() is called after the browser event has already occurred.
// we once tried to use readyState "interactive" here, but it caused issues like the one
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
if ( document.readyState === "complete" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
setTimeout( jQuery.ready, 1 );
// Standards-based browsers support DOMContentLoaded
} else if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );
// If IE event model is used
} else {
// 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 );
// 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) {}
if ( top && top.doScroll ) {
(function doScrollCheck() {
if ( !jQuery.isReady ) {
try {
// Use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
top.doScroll("left");
} catch(e) {
return setTimeout( doScrollCheck, 50 );
}
// and execute any waiting functions
jQuery.ready();
}
})();
}
}
}
return readyList.promise( obj );
};
那末,又是谁来挪用呢?当然是须要的时刻,在我们挪用 ready
函数的时刻,才须要注册这些推断页面是不是完整加载的处置惩罚,这段代码在 1.8.3
中位于代码的 #244
行,以下所示:
ready: function( fn ) {
// Add the callback
jQuery.ready.promise().done( fn );
return this;
}
在页面上援用 jQuery
剧本库以后,实行了 jQuery
的初始化函数,初始化函数中创建了 ready
函数。我们在经由过程 ready
函数注册事宜处置惩罚之前,jQuery
完成了页面检测代码的注册。如许。当页面完整加载以后,我们注册的函数就被挪用了。
八、参考
1.jQuery 的 ready 函数是怎样事情的?
2.jQuery ready函数完成道理
3.deferred.done()