Reputation: 1139
I have a simple chrome extension, which works with page's DOM (it looks for "something" what looks like login forms). Problem is, that many pages has "dynamic" login forms - its code is loded when needed. That's why body's onload event is not enough.
So I've created mutation observer and execute my procedure each time DOM changes (there will be some restrictions in the future - many of these changes does not affect my purpose)
Because of some intervals I have to implement delayed execution of my procedure over updated DOM (the time 500 is only for testing purpose)
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);
The problem is, that setTimeout keeps firing to infinity, which makes the page pretty lazy after some time. In Chrome JS console is number of 'executed' messages still increasing.
I'm aware of clearTimeout(timer)
, but I'm not able to use it right - so my_procedure
is executed only once for each DOM change.
EDIT: my_procedure
is actually 3rd-party library function, so I don't want (or can) to change it - the function starts the whole form-classification logic.
Thank yout for advice.
Upvotes: 0
Views: 1753
Reputation: 9788
The reason why setTimeout
seems to fire infinity, is that it actually fires as many times as there is e.g. new elements added to the DOM. So basically, it assigns 3 setTimeout
calls if 3 divs are added to the DOM. The reason being, that you are doing it inside mutations.forEach(function(mutation) { ... }
loop.
Therefore, the solution is to remove the loop and only assign one setTimeout
call at higher level which will fire when the DOM changes:
// create an observer instance
var observer = new MutationObserver(function(mutations) {
// fired when a mutation occurs
timer = setTimeout(function () {
console.log("executed");
// my_procedure();
}, 500);
});
Below is the full example, it should display "executed" once (after 3 second) to console when the DOM is actually changed, even though we add 3 new divs.
The code:
// 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);
*/
Cheers.
Upvotes: 1
Reputation: 7666
In my_procedure() you can use
clearTimeout(timer);
in the first line to avoid multiple occurence
UPDATED CODE:
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);
Upvotes: 2
Reputation: 3306
You have got only 1 var "timer" and then you use ".forEach()" on your "mutations" !
So you overwrite timer each time, that's why if you set clearTimeout in my_procedure it doesn't work (it will stop only 1 timer, the last of the mutations).
Doesn't it ?
Upvotes: 0