【js】实现DOMReady
2015-09-14 本文已影响1914人
歇歇
什么是DOMReady?
一个被封装的方法,用以当浏览器生成DOM树结构后就开始解析某些js代码。
为什么需要DOMReady?
在初学js时,我们都知道使用window.onload
用以保证页面的所有资源都加载完毕后才执行当中的js代码,否则当js在title中定义或则引用时会报错:不能为空节点添加某某属性云云。是的,onload的确是一个简单易用的方法,但随着我们学习的深入,当我们构建的页面存在大量图片或其他需要较长时间加载的资源时,显然让js等待这些费事的资源加载完毕再执行是非常不合理且形成糟糕的用户体验。这时我们有了新的需求,需要在DOM树生成后&其他资源加载以及渲染前就执行js代码,所以DOMReady出现了,驾着七彩祥云而来...
实现DOMReady的原理
在说及DOMReady的原理之前,我们需要知道渲染引擎的渲染(浏览器把请求的html显示出来的过程)基本流程:
1.解析HTML,构建DOM树(构建DOM节点);
2.构建渲染树(解析样式信息,包括外部的css文件、style标签中的样式,按优先级解析)。渲染树由一些包含有各种属性的矩形组成,他们将会按照正确的顺序显示到屏幕上;
3.布局渲染树(布局DOM节点),执行布局的过程,将确定每个节点在屏幕上的确切坐标;
4.绘制渲染树(绘制DOM节点,即遍历渲染树),使用UI后端层来绘制每个节点。

DOMReady的原理:在构建了DOM树之后就开始解析js,而不是等待页面渲染完毕。
实现策略
IE8(包括)之前版本由于不支持符合W3C规范的DOMContentLoaded事件,所以需要用hack实现兼容。所以如下图所示,需要在DOMReady方法中同时提供下面两种策略。

实现代码
function myDOMReady(fn){
//判断如果支持addEc=ventListener(非IE--IE支持的是attachEvent)则绑定DOMContentLoaded事件
if(document.addEventListener){
document.addEventListener("DOMContentLoaded",fn,false);
}else{
IEContenLoaded(fn);
}
//IE下模拟DOMContentLoaded
function IEContenLoaded(fn){
var done = false;
//只执行一次用户的回调函数init
var init = function(){
if(!done){
done = true;
fn();
}
}
(function(){
try{
//DOM树未创建完之前调用doScroll会抛出错误
window.document.documentElement.doScroll("left");
}catch(error){
//延迟再执行,arguments.callee调用自己
setTimeout(argument.callee,1);
return;
}
//没有错误表示DOM树创建完毕,执行用户回调
init();
})();
//监听document的加载状态
window.document.onreadystatechange = function(){
//如果用户是在DOMReady之后调用的函数立即执行用户回调
if(window.document.readyState == 'complete'){
window.document.onreadystatechange=null;
init();
}
}
}
}
下面附上不知谁整理的主流JS框架中DOMReady事件的实现