是否有IE渲染完成事件?

时间:2011-08-04 16:05:03

标签: javascript jquery dom internet-explorer-8

在尝试确定页面加载20秒的原因时,我在IE8中发现了一些奇怪的行为。

情况就是这样。

我进行了ajax调用,它返回并且回调看起来像这样

$("#StoreDetailsContainer").html($(tableHtml));
var StoreDetailsTable = $("#StoreDetailsTable");
StoreDetailsTable.tablesorter({ sortList: [[0, 0]], cssChildRow: "SubTable" });
StoreDetailsTable.filtertable({ cssChildRow: "SubTable" });

但是,这段代码需要20秒才能完成。

我正在乱搞,计时,并在方法之间弹出警报,突然间,只用了6秒钟。我玩了一点,发现如果我在.html()调用之后引入延迟,并且在我尝试操作DOM之前,页面渲染速度更快。它现在看起来像这样

$("#StoreDetailsContainer").html($(tableHtml));
window.setTimeout(function() {
    var StoreDetailsTable = $("#StoreDetailsTable");
    StoreDetailsTable.tablesorter({ sortList: [[0, 0]], cssChildRow: "SubTable" });
    StoreDetailsTable.filtertable({ cssChildRow: "SubTable" });
}, 100);

尽管在该过程中额外添加了1/10秒,它也只需要6秒。

我的理论是,由于IE在尝试使用之前没有通过.html()调用完全呈现给屏幕,因此会发生某种锁定。

有没有办法确定IE何时完成了.html()添加到DOM的内容的渲染,所以我不需要在setTimeout调用中使用任意值?

5 个答案:

答案 0 :(得分:6)

你的分析几乎就在现场。让我试着解释为什么setTimeout正在发挥作用。

如果您看一下关于DOM渲染的精彩article,您就会明白.html()会导致 重排 。< / p>

现在有了接下来的两行,发生的事情是你正在占用浏览器的渲染线程。在尝试重排之前,浏览器可以选择等待脚本执行完成(以避免多次重排或缓冲所有更改)。

解决方案 - 我们需要告诉浏览器我们的html更改已完成,您可以完成渲染过程。这样做的方法 - 1)结束你的脚本2)使用setTimeout来执行浏览器。

执行setTimeout延迟0ms也有效,因为setTimeout基本上放弃了对sript块的控制。动画相关脚本非常依赖setTimeoutsetInterval的原因之一。

另一个潜在的改进是使用documentFragments,John Resig简洁地解释here

我认为将这两者结合起来会产生更快的速度,但当然,在进行分析之前无法知道!

答案 1 :(得分:3)

您可以将单个像素图像添加到回调响应中,在.html(..)之后从DOM获取该图像并附加到其onload事件。我无法想象图像的onload事件可能会在浏览器渲染之前触发。

确保图像在src中具有唯一标识符,以便它不会被缓存...

你遇到的奇怪问题 - 我相信有人会提供更优雅的解决方案:)

答案 2 :(得分:2)

调用setTimeout至少在指定时间内延迟给定函数,但在当前脚本执行完成之前永远不会运行。也就是说,你可以用0秒替换你的超时。

另一种可能值得尝试的方法是访问生成内容的某些布局属性(例如 StoreDetailsContainer 的高度)。这样,您可以在将控制权返回给脚本之前强制IE完成渲染,因为它只能在完成计算布局后提供脚本请求的正确值。

可能有帮助的第三个猜测是确保用页面的布局解析HTML。这样可以防止一次又一次地绘制半完成布局。为此,您可以在调用html之前从DOM中分离 StoreDetailsContainer 元素。现在,IE已经改变了构造DOM而不影响布局。之后,您将 StoreDetailsContainer 重新附加到DOM中。与普通innerHTML集相比,此分离和重新附加容器允许您控制何时解析HTML以构建DOM树以及何时计算布局。

答案 3 :(得分:0)

试试这段代码。在ready事件之后触发load事件,因此它可能会起作用。

$(document).ready(function(){
  $("#StoreDetailsContainer").html($(tableHtml))
  });
$(window).load(function(){
  $("#StoreDetailsTable").tablesorter({ sortList: [[0, 0]], cssChildRow: "SubTable" }).filtertable({ cssChildRow: "SubTable" });
  });

答案 4 :(得分:0)

我认为它可以像这样工作:

$("#StoreDetailsContainer").html($(tableHtml))
.find("#StoreDetailsTable")
.tablesorter({ sortList: [[0, 0]], cssChildRow: "SubTable" })
.filtertable({ cssChildRow: "SubTable" });