浏览器在使用innerHTML插入Ajax响应之前不更新文本

时间:2011-02-03 19:09:38

标签: javascript

我正在使用具有树状结构树的CMS,因此我试图模拟用于浏览其C驱动器的Windows资源管理器。所以最初我在根级别列出页面,并使用onClick事件和AJAX,单击根页面将显示下面的页面,在我创建/分配的DIV中。

一切正常,我在xmlhttp.send运行时在另一个DIV中显示动画加载gif,当if (xmlhttp.readyState==4 && xmlhttp.status==200)为真时关闭。

问题在于,当存在大量子页面(大约1000个并且是,客户端创建它们)时,AJAX完成并且它到达document.getElementById(DivId).innerHTML = xmlhttp.responseText;,这导致gif停止旋转。所以我用Google搜索了,这似乎是一个浏览器问题。

所以我想,我会在AJAX调用期间使用gif并在浏览器渲染新的innerHTML时显示等待文本。然而,尽管它需要几秒钟,但是这个文本永远不会显示出来,我只是看到了冻结的gif然后再渲染了“完成”文本。

如果我注释掉“完成”行,则会显示等待文本。

代码如下:

function getPages(page_id, DivId)
{
    var loadingicon_div = "page_" + page_id + "_loadingicon";
    var loading_icon = 'image here, not allowed to post images..'; 

    document.getElementById(loadingicon_div).innerHTML = loading_icon;

    xmlhttp = new GetXmlHttpObject();
    xmlhttp.onreadystatechange = function() 
                    { 
                        if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
                        {
                            document.getElementById(loadingicon_div).innerHTML = "Retrieved pages from the server, please wait while your browser displays them ...";
                            document.getElementById(DivId).innerHTML = xmlhttp.responseText;
                            document.getElementById(DivId).style.padding="5px";
                            document.getElementById(loadingicon_div).innerHTML = "done";
                        }
                    }

    var url="tree_ajax.php";

    xmlhttp.open("GET",url,true);
    xmlhttp.send(null);
}

2 个答案:

答案 0 :(得分:0)

你应该真正使用一个框架。我最近使用内置于extjs的ajax treeview掀起了几乎相同的东西。相信我,这将为您节省很多麻烦。跨浏览器dom是PITA。

我知道这不能解答您的具体问题,但请听取我的意见!

http://dev.sencha.com/deploy/dev/examples/tree/reorder.html

答案 1 :(得分:0)

解决这个问题的唯一方法是重新设计。 - 不,不是,但你真的应该 - 继续阅读;)

动画gif停止动画的原因是因为浏览器正在使用它的所有肌肉将新元素附加到DOM并在完成后重新绘制/重新绘制页面。根本没有cputime让它为gif设置动画。

计算机/浏览器越慢,你就越会看到这个问题,但是如果你构建一个包含足够元素的页面,你就可以在4ghz计算机上的谷歌浏览器中实现这一点。

当谈到javascript / DOM操作/渲染/绘画时,浏览器本质上就是一个单线程的野兽,因此它一次只能做一件事。

它试图通过将复杂的操作分解为切片然后运行这些切片来使这看起来像是可以同时执行多个操作来弥补这一点(就像操作系统在单核机器上所做的那样,尽管很多简单)

但是一旦你得到一个足够复杂的dom结构,重新渲染/重新绘制的切片变得如此之大,以至于浏览器似乎在它发生时冻结。

至于没有出现的文字:

如果你希望在进行大型DOM操作之前使一个小的DOM操作生效(比如插入你的文本),你需要让浏览器把它当作两个单独的切片(它不想要do,因为DOM操作和随后的重新渲染/重新绘制非常昂贵)

要执行此操作,请使用setTimeout在javascript中中断callstack。

这将允许浏览器在下一次DOM操作和随后的重新渲染/重新绘制之前进行重新渲染/重新绘制。

通常只需要基于零延迟的setTimeout即可,因为setTimeout本身会破坏callstack,但在某些情况下,您需要一个小延迟 - 玩它并且找到你的甜点:)

示例:

//do small DOM manipulation here
setTimeout(function(){
  //do major DOM manuipulation here
},0);