huankfy

明月出天山,苍茫云海间

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

    先看一下问题:

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节点的情况。
    也许你会想,为什么不直接在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加载完成!
    对Mozilla系列的浏览器(如ff/googlechrome),可以:
1 // for Mozilla browsers
2 if (document.addEventListener) {
3    document.addEventListener("DOMContentLoaded", init, false);
4 }
    其中init执行createDom和修改后的operateDom.下同。
    IE支持条件编译(js是解释执行的,这里找不到合适的词来表述,看下面的代码就知道了)。在IE系列的浏览器中,可以:
Code
    如果在页面里面这么写:
Code
    在IE系列的浏览器是正常的,其它浏览器会忽略defer属性,将外部js文件加载进来。这里ie_onload.js里面只有init函数。 对其它系列的浏览器,这么写: window.onload=init. 综合起来,init就会执行多次了,就不是一次。同上面处理operateDom一样,给init增加一个哨位即可:     1 function init() {
 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 };

   至此,问题解决。

参考资料:The window.onload Problem - Solved!





posted on 2008-09-06 19:22  Yanbo.Hu  阅读(1346)  评论(0编辑  收藏  举报