我有一个简单的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
实际上是第三方库函数,因此我不想(或可以)更改它 - 该函数启动整个表单分类逻辑。
感谢您的建议。
答案 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个定时器,最后一个突变)。
不是吗?