views:

506

answers:

4

I'm using jQuery to listen to DOMSubtreeModified event, and then execute a function. What I need is a way to only run a function once per event burst. So in this case, the event will only run after 1 second, and again after 3 seconds. What is the best way to do this?

jQuery

$(function(){

 setTimeout(function(){
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
 },1000);

 setTimeout(function(){
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
 },3000);

 $('#container').bind('DOMSubtreeModified',function(){
  console.log('event');
        functionToRun();
 });

});

HTML

<div id="container"></div>


Update
The setTimeout function are there just to emulate my problem. I need a solution without changing the setTimeout code. The problem I'm having is that I get burst of DOMSubtreeModified events, and I need to get only one per burst.

A: 

This seems to be what you're looking for:

$(
  function()
  {
    setTimeout 
    (
      StartWatching,
      1000
    );
  }
);

function StartWatching()
{
  $('#container')
     .bind(
            'DOMSubtreeModified',
            function()
            {
              console.log('event');
              StopWatchingAndStartAgainLater();
            }
          );
}

function StopWatching()
{
  $('#container')
      .unbind('DOMSubtreeModified');
}

function StopWatchingAndStartAgainLater()
{
  StopWatching();
  setTimeout
  (
    StartWatching,
    3000
  );
}

This enforces the following flow:

Document.Ready
Create DOM watching event after one second
On event, turn off event and recreate it after three seconds, rinse, repeat
David Andres
Syntax error, if I fix it, it still only prints out 1 event.
mofle
@mofle...made some slight changes to how the setTimeout function is called. I'll test it locally to verify this works.
David Andres
@mofle...confirmed that the above works when I change StartWatching to simple append to a div and make a call to StopWatchingAndStartAgainLater. If this still fails for you, chances are then that something is not working with the bind to the DOMSubtreeModified event.
David Andres
@mofle....and verified it works with DOMSubtreeModified in FireFox 3.5 and Google Chrome, at least. This event does not appear to fire in IE 7.0.
David Andres
A: 

try using one() handler

documentation

dd
I'm sorry I can't elaborate and rewrite your code, I'm in Hurry. But I can do that later if you won't be able to figure it out.
dd
Already tried it, but it only gives me one event from the first event burst (the first timeout), and nothing on the second burst.
mofle
+1  A: 

Solved it myself.

$(function(){

 setTimeout(function(){
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
 },1000);

 setTimeout(function(){
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
 },1100);

 setTimeout(function(){
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
  $('#container')[0].innerHTML = 'test';
 },3000);

 addDivListener();

 });

 function addDivListener() {
    $('#container').bind('DOMSubtreeModified',function(){
     functionToRun();
     $(this).unbind('DOMSubtreeModified');
  setTimeout(addDivListener,10); 
    });
 }

 function functionToRun(){
    console.log('event');
 }

This prints out event 3 times in the Firebug console, and is accurate down to 100 ms.

mofle
+2  A: 

Alternate method, which will control the rate of any function.

// Control the call rate of a function.
//  Note that this version makes no attempt to handle parameters
//  It always induces a delay, which makes the state tracking much easier.
//    This makes it only useful for small time periods, however.
//    Just clearing a flag after the timeout won't work, because we want
//    to do the the routine at least once if was called during the wait period.
throttle = function(call, timeout) {
  var my = function() {
    if (!my.handle) {
      my.handle = setTimeout(my.rightNow, timeout);
    }
  };
  my.rightNow = function() {
    if (my.handle) {
      clearTimeout(my.handle);
      my.handle = null;
    }
    call();
  };
  return my;
};
Justin Love