2014-07-23 25 views
0

我有一个简单的扩展,它与页面的DOM一起工作(它寻找“东西”,看起来像登录表单)。问题在于,许多页面都有“动态”登录表单 - 它的代码在需要时被封装。这就是为什么body的onload事件不够。setTimeout持续发射

所以我创建突变观察者和执行我的程序每次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实际上是第三方库函数,所以我不想(或可以)改变它 - 该函数启动整个表单分类逻辑。

谢谢你的建议。

+0

'my_procedure()'做了什么? – putvande

+0

forEach()将循环你的动作..所以setTimeout触发多次 – PraJen

+0

'my_procedure'实际上并不是我的 - 我想演示,它的代码工作,我只需要处理它的调用。对帖子做了编辑注释。 – dakov

回答

2

在my_procedure的(),您可以使用

clearTimeout(timer); 

在第一线,以避免多重occurence

更新的代码:

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); 
+0

downvote的原因? – V31

+0

我误读了sry! –

+0

不用担心@Antoine – V31

0

你只拿到了1 VAR“计时器“然后你在你的”突变“上使用”.forEach()“!

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

不是吗?

1

setTimeout似乎开火无穷的原因是,它实际上触发了多次,例如,添加到DOM的新元素。所以基本上,如果将3个div添加到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); 

}); 

下面是完整的例子,它应该显示“已执行”一次(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); 
*/ 

干杯。

+1

这使得完美的感觉,我真的不知道为什么我使它如此复杂 - my_procedure无论如何评估整个DOM。 – dakov

+0

@dakov没有问题,我注意到,在调试时,你可能已经使用mutation.addedNodes.length :)嵌套太深的实际setTimeout检查:)这就是为什么它是值得简化的,因为它被称为没有这样做与回调在第一位。我建议只有在你真的需要更多地了解你添加的元素时,才会使用Elastic Loop for each循环。 –

+0

@dakov和请,作为回答接受或要求澄清,如果仍有困扰你,我更新了我的答案,告诉原因首先你的代码有什么问题。 :) –