Open Quickeryi opened 7 years ago
jQuery的ready方法执行的时机是在DOM准备就绪后,而不是不是等待所有资源加载完毕,即onload事件触发时执行
ready
DOM
onload
需要清楚dom什么时候ready,需要先知道浏览器整个渲染步骤:
dom
HTML
CSS
CSSOM
而根据Navigation Timing API可以更加清晰的知道在上述整个过程中,页面逐步触发的事件信息:
Navigation Timing API
解析阶段: [ domLoading -> domInteractive -> [domContentLoadedEventStart -> domContentLoadedEventEnd] -> domComplete]
domLoading
domInteractive
domContentLoadedEventStart
domContentLoadedEventEnd
domComplete
domContentLoaded
加载资源阶段:[loadEventStart -> loadEventEnd]
loadEventStart
loadEventEnd
loadEvent
结论:所以 dom ready 发生在 domContentLoaded 阶段
dom ready
根据上述理论,我们知道dom ready 发生的时机,但是不同的浏览器在此时机的表现不同,或者说开发者通过js获取dom ready状态的方法不同
js
DOMContentLoaded
readystatechange
document.readyState
document.readyState == complete
doScroll
有了上述理论分析,我们贴出原生的jQuery.ready实现
jQuery.ready
let ready = (fn) => { let completed = () => { if (document.addEventListener) { document.removeEventListener('DOMContentLoaded', completed, false); window.removeEventListener('load', completed, false); } else if (document.attachEvent) { document.detachEvent('onreadystatechange', completed); window.attachEvent('onload', completed); } fn(); }; /** * 如果我们注册 ready 函数的时间点太晚了,页面已经加载完成之后,那么直接执行 fn */ if (document.readyState == 'complete') { setTimeout(fn, 1); } else if (document.addEventListener) { document.addEventListener('DOMContentLoaded', completed, false); // 当触发不了 DOMContentLoaded 时,只能优雅降级 window.addEventListener('load', completed, false); } else { // IE document.attachEvent('onreadystatechange', completed); window.attachEvent('onload', completed); // If IE and not a frame let top = false; try { top = window.frameElement == null && document.documentElement; } catch(e) {} if (top && top.doScroll) { (function doScrollCheck() { try { top.doScroll("left"); } catch (e) { return setTimeout(doScrollCheck, 50) } fn(); })(); } } };
jQuery的
ready
方法执行的时机是在DOM
准备就绪后,而不是不是等待所有资源加载完毕,即onload
事件触发时执行dom.ready
需要清楚
dom
什么时候ready
,需要先知道浏览器整个渲染步骤:HTML
标记并构建DOM
树CSS
标记并构建CSSOM
树DOM
与CSSOM
合并成一个渲染树而根据
Navigation Timing API
可以更加清晰的知道在上述整个过程中,页面逐步触发的事件信息:解析阶段: [
domLoading
->domInteractive
-> [domContentLoadedEventStart
->domContentLoadedEventEnd
] ->domComplete
]domLoading
:这是整个过程的起始时间戳,浏览器即将开始解析第一批收到的HTML
文档字节domInteractive
:表示浏览器完成对所有HTML
的解析并且DOM
构建完成的时间点domContentLoaded
:包含domContentLoadedEventStart
和domContentLoadedEventEnd
,一般表示 DOM 和 CSSOM 均准备就绪的时间点domComplete
:所有处理完成,并且网页上的所有资源(图像等)都已下载完毕加载资源阶段:[
loadEventStart
->loadEventEnd
]loadEvent
:包含上述两个阶段,此时浏览器触发onload
事件结论:所以
dom ready
发生在domContentLoaded
阶段兼容性
根据上述理论,我们知道
dom ready
发生的时机,但是不同的浏览器在此时机的表现不同,或者说开发者通过js
获取dom ready
状态的方法不同domContentLoaded
会触发DOMContentLoaded
事件readystatechange
:如果浏览器存在readystatechange
事件时,浏览器会在解析的阶段各个阶段触发这个事件,并且document.readyState
的值不断改变(这跟ajax非常相似),当document.readyState == complete
时,表示dom
加载完毕。(ps:这个事件不太可靠,比如当页面中存在图片的时候,可能反而在 onload 事件之后才能触发,换言之,它只能正确地执行于页面不包含二进制资源或非常少或者被缓存时作为一个备选吧)doScroll
:IE浏览器文档中说明,当页面DOM
未加载完成时,调用doScroll
方法时,会产生异常,那么反过来正好可以检测DOM
是否加载完毕jQuery.ready 实现
有了上述理论分析,我们贴出原生的
jQuery.ready
实现