先看一下问题:
1 window.onload=function(){
2 createDom();
3 operateDom();
4 //code stuff
5 }
其中 createDom()通过异步请求取得大量数据,然后组织起来;operateDom()是通过遍历操作createDom生成的节点。问题出现了:页面显示的并不是我们想要的效果。为什么?operateDom并不能总是取到生成的dom节点。由于生成的dom节点附加到页面dom树的时候存在着延迟,所以在createDom里面数据量比较大、生成dom节点比较多的时候,这种时间差会很大(对机器而言)。虽然createDom里面的语句执行完毕,接下来执行operateDom,但那些生成的节点也许还没有完全附加到dom树上面,所以就存在取不到dom节点的情况。2 createDom();
3 operateDom();
4 //code stuff
5 }
也许你会想,为什么不直接在createDom里面在生成那些dom的时候直接操作,而是重新进行遍历操作?问题在于createDom和operateDom并不是同一个开发人员写的,也有可能是调用公用的东西,所以更不可能去改createDom了。这里只是为了举例方便。
怎么办?setTimeout?setTimeInterval?
setTimeout自然不可取,我们并不知道时间差是多少,设的太长了,用户体验不好,设的太短了,达不到我们的目的。setTimeInterval可以,但这会频繁的执行,我们只需要它执行一次。针对setTimeInteval,折中的解决办法是设置哨位监视。改动一下:
1 operateDom(){
2 if(operateDom.called)
3 return;
4 // code stuff
5 }
问题解决了?没有。我们要操作的是Dom,onload会直到页面所有内容都加载完成才执行。如果页面有太多的图片,那就只用等了。对用户来说,等的时间就是加载图片的时间,然后加上我们处理dom节点的时间,用户体验就差了。我们需要的仅仅是dom加载完成!2 if(operateDom.called)
3 return;
4 // code stuff
5 }
对Mozilla系列的浏览器(如ff/googlechrome),可以:
1 // for Mozilla browsers
2 if (document.addEventListener) {
3 document.addEventListener("DOMContentLoaded", init, false);
4 }
其中init执行createDom和修改后的operateDom.下同。2 if (document.addEventListener) {
3 document.addEventListener("DOMContentLoaded", init, false);
4 }
IE支持条件编译(js是解释执行的,这里找不到合适的词来表述,看下面的代码就知道了)。在IE系列的浏览器中,可以:

1 // for Internet Explorer
2 /*@cc_on @*/
3 /*@if (@_win32)
4 document.write("<script defer src=ie_onload.js><"/script>");
5 /*@end @

<!--[if IE]><script defer src="ie_onload.js"></script><![endif]
2 // quit if this function has already been called
3 if (arguments.callee.done) return;
4
5 // flag this function so we don't do the same thing twice
6 arguments.callee.done = true;
7
8 createDom();
9 setTimeInterval("operateDom()",100);
10 // do stuff
11 };
3 if (arguments.callee.done) return;
4
5 // flag this function so we don't do the same thing twice
6 arguments.callee.done = true;
7
8 createDom();
9 setTimeInterval("operateDom()",100);
10 // do stuff
11 };
至此,问题解决。