我如何知道对 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 描述的完全一样的场景,我无法避免“基于计时器的解决方案”。所以,我只是分享我开发的解决方案,以防万一还有人对此有疑问。

我讨厌在我的代码中使用 setTimeouts 和 setIntervals。所以,我创建了一个小插件,你可以把它放在你认为最好的地方。我使用了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/文本的更改

jQuery无法识别对html的更改[重复]

怎么用jQuery实现鼠标移入样式滑动显示

如何更改 JQuery.DataTable 中特定单元格的背景?

如何使用 jquery 动态更改 iframe 中的内容?

如何使用 Jquery 重新排序 Gridview 行?