我如何知道对 jquery html() 的更改何时完成?
Posted
技术标签:
【中文标题】我如何知道对 jquery html() 的更改何时完成?【英文标题】:How can I tell when changes to jquery html() have finished? 【发布时间】:2011-02-03 22:21:59 【问题描述】:我正在使用 jQuery 来更改标签的 html,而新的 HTML 可以是很长的字符串。
$("#divToChange").html(newHTML);
然后我想选择在新 HTML 中创建的元素,但是如果我将代码紧跟在上面的行之后,它似乎会创建一个带有长字符串的竞争条件,其中 html() 所做的更改可能不一定是完成渲染。在这种情况下,尝试选择新元素并不总是有效。
我想知道的是,当对 html() 的更改完成渲染时,是否会触发事件或以其他方式得到通知?我遇到了 jQuery watch 插件,它可以作为解决方法使用,但并不理想。有没有更好的办法 ?
【问题讨论】:
JS 是单线程的,所以这真的不应该发生......你能在 jsbin.com 上发布一个重现吗? @Michael - 查看 jsFiddle,发现它更有用:jsfiddle.net 【参考方案1】:正如评论者已经提到的,javascript 是单线程的,所以你无法获得竞争条件。
然而,可能会让您感到困惑的是,UI 不会基于 JavaScript 自行更新,直到线程完成。这意味着整个方法必须完成,包括调用 html(...)
之后的所有代码,然后浏览器才会呈现内容。
如果您在调用html(...)
后的代码依赖于在继续之前重新计算的页面布局,您可以执行以下操作:
$("#divToChange").html(newHTML);
setTimeout(function()
// Insert code to be executed AFTER
// the page renders the markup
// added using html(...) here
, 1);
在 JavaScript 中使用 setTimeout(...)
和 1
会延迟执行,直到调用函数中的当前 JavaScript 代码完成并且浏览器更新了 UI。这可能会解决您的问题,但除非您能提供一个可重现的错误示例,否则很难判断。
【讨论】:
Reflow 不会等到所有正在运行的代码完成。依次运行多个操作,每个操作都可能导致回流,这将比单个操作遭受更多的回流性能损失(即使回流的后果是相同的)。 @eyelidlessness 除非我误解了你的意思,否则这根本不是真的。这可以通过我放在一起的这个简单测试来证明:jsbin.com/avuli/6 单击文档一次,代码将执行while
循环 5 秒。请注意,直到 5 秒结束时 UI 才会更新。第二次单击时,我使用计时器循环更新 UI。这一次,您会注意到 UI 会随着 DOM 的变化而“实时”更新。
澄清一下,“重排”并不一定意味着文档会在视觉上得到更新。您的 while
循环是一个阻塞操作,因此在完成之前不会发生视觉更新。但是每次操作都会发生重排,因此即使页面在视觉上停滞不前,在 DOM 中查询依赖于重排的数据也会为您提供正确的结果。查看我对您的脚本的编辑:jsbin.com/ayulu3(第一次点击后查看控制台)
为了扩展主题,每个操作都会发生回流这一事实是批处理 DOM 操作在只能强制单个回流时执行得更好的原因(例如,附加单个 @987654330 @ 或 DocumentFragment
包含一组要附加的元素)。【参考方案2】:
7 年后,我遇到了与@mikel 描述的完全一样的场景,我无法避免“基于计时器的解决方案”。所以,我只是分享我开发的解决方案,以防万一还有人对此有疑问。
我讨厌在我的代码中使用 setTimeout
s 和 setInterval
s。所以,我创建了一个小插件,你可以把它放在你认为最好的地方。我使用了setInterval
,但您可以将其更改为 setTimeout 或您想到的其他解决方案。这个想法只是创建一个承诺并继续检查元素。一旦准备好,我们就会解决承诺。
// jquery.ensure.js
$.ensure = function (selector)
var promise = $.Deferred();
var interval = setInterval(function ()
if ($(selector)[0])
clearInterval(interval);
promise.resolve();
, 1);
return promise;
;
// my-app.js
function runWhenMyElementExists ()
// run the code that depends on #my-element
$.ensure('#my-element')
.then(runWhenMyElementExists);
【讨论】:
非常好,我正在寻找这个非常简单和简短的代码。它肯定也对我有用。【参考方案3】:使用 .ready jQuery 函数
$("#divToChange").html(newHTML).ready(function ()
// run when page is rendered
);
【讨论】:
以上是关于我如何知道对 jquery html() 的更改何时完成?的主要内容,如果未能解决你的问题,请参考以下文章
jQuery 事件:检测对 div 的 html/文本的更改