首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》建议127:妥善使用DOMContentLoaded事件

关灯直达底部

在传统事件模型中,load是页面中最早被触发的事件。不过当使用load事件来初始化页面时可能会存在一个问题,那就是当页面中包含很大的文件时,load事件需要等到所有图像全部载入完成之后才会被触发。这时可以考虑使用DOMContentLoaded事件,作为DOM标准事件,它是在DOM文档结构加载完毕的时候被触发的,要比load事件先被触发。目前,Firefox和Opera新版本已经支持了DOMContentLoaded事件,而IE和Safari浏览器还不支持。

在标准DOM中可以这样设计:


<html>

<head>

<script language="javascript"type="text/javascript">

window.onload=f1;

if(document.addEventListener){

document.addEventListener("DOMContentLoaded",f,false);

}

function f{

alert("我提前执行了");

}

function f1{

alert("页面初始化完毕");

}

</script>

</head>

<body>

<img src="Winter.jpg">

</body>

</html>


这样,在图片加载之前,会弹出“我提前执行了”的提示信息,而在图片加载完毕后才会弹出“页面初始化完毕”提示信息。这说明在页面HTML结构加载完毕之后触发DOMContentLoaded事件,也就是说,在文档标签加载完毕触发该事件,并调用函数f,然后在文档所有内容加载完毕(包括图片下载完毕)才触发load事件,并调用函数f1。

由于IE不支持DOMContentLoaded事件,为了实现兼容处理,我们需要运用一点小技巧,即在文档中写入一个新的script元素,不过该元素会延迟到文件最后加载。在使用script元素的onreadystatechange方法进行类似的readyState检查后及时调用载入事件,代码如下:


if(window.ActiveXObject){

document.write("<script id=ie_onload defer src=javascript:void(0)><//script>");

document.getElementById("ie_onload").onreadystatechange=function{

if(this.readyState=="complete"){

this.onreadystatechange=null;

f;

}

}

}


在写入的<script>标签中包含了defer属性,defer表示“延期”的意思,使用defer属性可以让脚本在整个页面加载完成之后再解析,而非边加载边解析。这对于只包含事件触发的脚本来说,可以提高整个页面的加载速度。与src属性联合使用,还可以使这些脚本在后台被下载,前台的内容则正常显示给用户。目前只有IE支持defer属性。在定义了defer属性后,<script>标签中就不应该包含document.write命令了,因为document.write将产生直接输出效果,并且不包括任何立即执行脚本要使用的全局变量或函数。

由于<script>标签在文档结构加载完毕之后才加载,因此只要判断它的状态就可以确定当前文档结构是否已经加载完毕,并触发响应的事件。

针对Safari浏览器,我们可以使用setInterval函数周期性地检查document对象的readyState属性,随时监控文档是否加载完毕,如果加载完成则调用回调函数,代码如下:


if(/WebKit/i.test(navigator.userAgent)){

var_timer=setInterval(function{

if(/loaded|complete/.test(document.readyState)){

clearInterval(_timer);

f;

}

},10);

}


把上面3段条件结构合并在一起即可实现兼容不同浏览器的DOMContentLoaded事件处理函数。