是否有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块的控制。 动画相关脚本非常依赖setTimeout
和setInterval
的原因之一。
另一个潜在的改进是使用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" });