setTimeout持续触发

setTimeout keeps firing

本文关键字:setTimeout      更新时间:2023-09-26

我有一个简单的chrome扩展,它与页面的DOM一起工作(它寻找"某些东西"看起来像登录表单)。问题是,许多页面都有"动态"登录表单——它的代码是在需要时加载的。这就是为什么body的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实际上是第三方库函数,所以我不想(或可以)改变它-函数开始整个形式分类逻辑。

谢谢你的建议。

在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);

为什么setTimeout似乎火无限的原因是,它实际上火灾有许多次,例如,新的元素添加到DOM。所以基本上,如果3div被添加到DOM,它会分配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);  
});

下面是完整的示例,当DOM实际更改时,即使我们添加了3个新div,它也应该在控制台显示一次"已执行"。

js提琴示例

代码:

// 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);
*/

欢呼。

你只有1 var "定时器",然后你使用".forEach()"对你的"突变" !

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