MutationObserver
s are async by specfication, in that they will wait for the current stack to be empty before it calls your callback function. This is useful so your callback is not called each time you make a change to the DOM but only after all your changes have been made. See how are MutationObserver callbacks fired?
If you look at the specification link you will notice the steps involved before a MutationEvent
are:
- MutationObserver gets notified of a mutation
- Appends the mutation to the current set of mutations since the last event/
takeRecords
- Call the callback function after the current stack is empty (this is why your code works as you expected with set timeout -
setTimeout
will call the function after the timeout and stack empties) - Empty the record queue and continue observing
Update sorry, to address your actual question, I'm thinking it may have to do with the alert
in the MutationObserver
callback. It definitely shouldn't take more than a couple of milliseconds for mutations to be processed and it should definitely occur before the setTimeout
. Anyway a solution that would definitely work is to add a queue processor in the MutationObserver callback instead of using a timeout.
function transact(callback){
var queue = [], listener; //queue of callbacks to process whenever a MO event occurs
/* Watch content area for mutations */
var observer = new MutationObserver(function(){ //made observer local
/* TODO: collect mutations in here */
alert('Mutations observed');
while(listener = queue.shift()) listener();
});
observer.observe(document.getElementById('content'), {
attributes: false,
childList: true,
characterData: false,
subtree: false
});
/* Perform the callback */
callback();
/* Stop observing */
//observer.disconnect();
queue.push(observer.disconnect.bind(observer));
}