是否有 IE 渲染完成事件?

发布于 2024-11-28 07:48:32 字数 1025 浏览 1 评论 0原文

在尝试确定页面加载时间为 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 秒。

我的理论是,由于在尝试使用 DOM 之前,IE 并未通过 .html() 调用将 DOM 完全渲染到屏幕上,因此会发生某种锁定。

有没有办法确定 IE 何时完成渲染通过 .html() 添加到 DOM 的内容,这样我就不需要在 setTimeout 中使用任意值称呼?

While trying to determine why a page was taking 20s to load, I found some odd behavior in IE8.

The scenario is this.

I make an ajax call, it returns and the callback looked something like this

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

However, this bit of code took 20s to complete.

I was messing around, timing things, and popping up alerts between methods, and suddenly, it took only 6s. I played around a little more to find that if I introduced a delay after the .html() call, and before I attempted to manipulate the DOM, the page rendered MUCH faster. It now looks like this

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

It also only takes 6s despite having an extra 1/10th of a second added to the process.

My theory is that because the DOM wasn't fully rendered to the screen by IE by the .html() call before attempting to work with it, there is some kind of locking happening.

Is there a way to determine when IE has finished rendering what was added to the DOM by .html() so I don't need to use an arbitrary value in a setTimeout call?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

早茶月光 2024-12-05 07:48:32

您的分析几乎已经到位。让我尝试解释一下为什么 setTimeout 会产生这种差异。

如果你看看这个伟大的关于 DOM 渲染的文章,你就会明白 .html()将导致回流发生。

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

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

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

另一个潜在的改进是使用 documentFragments,John Resig 此处< /a>

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

You're almost on the spot with your analysis. Let me attempt to explain why setTimeout is making the difference.

If you look at this great article about DOM rendering, you'll understand that .html() will cause a reflow to happen.

Now with the next two lines, what is happening is that you're tying up the browser's rendering thread. Browsers may choose to wait till script execution completes before attempting a reflow (to avoid multiple reflows or to buffer all changes).

The solution - we need to tell the browser that our html changes are done and you can complete the rendering process. The way to do it - 1) end your script 2) use setTimeout to yield the execution to the browser.

Doing a setTimeout with 0ms delay also works because setTimeout basically relinquishes control of the sript block. One of the reasons why animation related script rely so heavily on setTimeout and setInterval.

Another potential improvement would be to use documentFragments, explained succinctly by John Resig here

I think combining these two should yield more speed but of course, no way to know until profiling is done!

め可乐爱微笑 2024-12-05 07:48:32

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

确保图像在 src 中有一个唯一的标识符,这样它就不会被缓存...

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

B

You could add a single pixel image to your callback response, get that image from the DOM after .html(..) and attach to its onload event. I can't imagine it's possible for the image's onload event to fire until the browser has rendered it.

Make sure the image has a unique identifier in the src so that it doesn't get cached...

Odd problem you're having though - I'm sure someone will offer a more graceful solution :)

B

猫瑾少女 2024-12-05 07:48:32

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

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

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

Calling setTimeout delays the given function at least for the specified time but it is never run before the current script execution finished. That said, you could replace your timeout with 0 seconds.

Another approach that might be worth trying is that you access some layout property of the generated content (for example height of StoreDetailsContainer). This way you force IE to finish rendering before returning control to your script since it can only provide the correct value that your script requested after finishing to calculate the layout.

Third guess that might help is that you ensure to parse the HTML out-with the page's layout. This would prevent painting half-done layouts over and over again. To do so, you could detach the StoreDetailsContainer element from the DOM prior your call to html. Now, IE has the change to construct the DOM without affecting the layout. After that you would re-append the StoreDetailsContainer into the DOM. Compared to a normal innerHTML set, this detaching and re-attaching of the container allows you to control when the HTML is parsed to build the DOM tree and when the layout is calculated.

倥絔 2024-12-05 07:48:32

试试这个代码。加载事件在就绪事件之后触发,因此它可以工作。

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

Try this code. The load event is fired after ready event, so it may work.

$(document).ready(function(){
  $("#StoreDetailsContainer").html($(tableHtml))
  });
$(window).load(function(){
  $("#StoreDetailsTable").tablesorter({ sortList: [[0, 0]], cssChildRow: "SubTable" }).filtertable({ cssChildRow: "SubTable" });
  });
情徒 2024-12-05 07:48:32

我认为它可以这样工作:

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

I think that it could work like this:

$("#StoreDetailsContainer").html($(tableHtml))
.find("#StoreDetailsTable")
.tablesorter({ sortList: [[0, 0]], cssChildRow: "SubTable" })
.filtertable({ cssChildRow: "SubTable" });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文