setTimeout一直在触发

时间:2014-07-23 10:45:45

标签: javascript dom settimeout

我有一个简单的chrome扩展,它与页面的DOM一起工作(它寻找“某些东西”看起来像登录表单)。问题是,许多页面都有“动态”登录表单 - 它的代码在需要时被编码。这就是为什么身体的onload事件还不够。

所以我创建了变异观察者并在每次DOM更改时执行我的程序(将来会有一些限制 - 许多这些变化不会影响我的目的)

由于某些时间间隔,我必须在更新的DOM上实现延迟执行我的程序(时间500仅用于测试目的)

var target = document.body;
var timer;

var observer = new MutationObserver(function(mutations) {

  mutations.forEach(function(mutation) {
    var count = mutation.addedNodes.length;

    if( count > 0) { 

        timer = setTimeout(function (){

                   console.log("executed");
                   my_procedure();

               }, 500);

    }
  });    
});

var config = { attributes: true, childList: true, characterData: true };

observer.observe(target, config);

问题是,setTimeout持续触发无穷大,这使得页面在一段时间后非常懒惰。在Chrome JS控制台中,“执行”消息的数量仍在增加。

我知道clearTimeout(timer),但我无法正确使用它 - 所以my_procedure只针对每次DOM更改执行一次。

编辑:my_procedure实际上是第三方库函数,因此我不想(或可以)更改它 - 该函数启动整个表单分类逻辑。

感谢您的建议。

3 个答案:

答案 0 :(得分:2)

在my_procedure()中,您可以使用

clearTimeout(timer); 

在第一行避免多次出现

更新后的代码:

var target = document.body;
var timer;
var counter = 0;

var observer = new MutationObserver(function(mutations) {

  mutations.forEach(function(mutation) {
    var count = mutation.addedNodes.length;
    clearTimeout(timer);
    if( count > 0) { 
        if(counter == 0){
        counter = 1;
        timer = setTimeout(function (){
                   console.log("executed");
                   my_procedure();

               }, 500);
        }else {
            clearTimeout(timer);
         }

    }
  });    
});

var config = { attributes: true, childList: true, characterData: true };

observer.observe(target, config);

答案 1 :(得分:1)

setTimeout似乎无穷无尽的原因在于它实际发射的次数与例如添加到DOM的新元素。所以基本上,如果向DOM添加了3个div,它会分配3个setTimeout调用。原因是,你是在mutations.forEach(function(mutation) { ... }循环中进行的。

因此,解决方案是删除循环并仅在更高级别分配一个setTimeout调用,这将在DOM更改时触发:

// create an observer instance
var observer = new MutationObserver(function(mutations) {

   // fired when a mutation occurs
   timer = setTimeout(function () {

      console.log("executed");
      // my_procedure();

   }, 500);  

});

以下是完整示例,它应显示"已执行"一旦(3秒后)在实际更改DOM时进行控制,即使我们添加了3个新的div。

<强> js fiddle example

代码:

// select the target node
var target = document.body,
    timer;

// create an observer instance
var observer = new MutationObserver(function(mutations) {

   // fired when a mutation occurs
   timer = setTimeout(function () {

      console.log("executed");
      // my_procedure();

   }, 500);  

});

// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };

// pass in the target node, as well as the observer options
observer.observe(target, config);

// Testing our observer
setTimeout(function() {
    document.body.innerHTML =  "<div>lol 1</div>";
    document.body.innerHTML += "<div>lol 2</div>";
    document.body.innerHTML += "<div>lol 3</div>";
}, 3000);

/* Comment out if you want to add more divs..
setTimeout(function() {
    document.body.innerHTML += "<div>lol 4</div>";
    document.body.innerHTML += "<div>lol 5</div>";
    document.body.innerHTML += "<div>lol 6</div>";
}, 5000);
*/

干杯。

答案 2 :(得分:0)

你只有1个var“计时器”,然后在你的“突变”上使用“.forEach()”!

所以你每次都要覆盖定时器,这就是为什么如果你在my_procedure中设置clearTimeout它不起作用(它将只停止1个定时器,最后一个突变)。

不是吗?