是否有IE渲染完成事件?

在尝试确定页面加载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调用中使用任意值?

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

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

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

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

如果你看一篇关于DOM渲染的好文章 ,你就会明白.html()会导致重排。

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

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

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

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

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

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

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

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

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

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

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

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