1

I have an event listener that is in a function. Both the listener and the emitter are in the same function.

When the event fires, a variable is incremented. So far so good. But when I call the function several times, the listener is triggered several times in the same function call.

var test = function() {    
    var completeStatus = 0;

    $(document).on('gt', function() {
        console.log(++completeStatus);
    });
    $(document).trigger('gt');
}

test();
test();
test();

It expect it to output 1 three times as the function is called three times. But it outputs:

0
1
0
2
1

Why is that and how to obtain the desired behaviour?

Here's a jsfiddle to try it out.

4
  • 1
    each time you call test, its binding a listener on the event gt and firing a gt event to all listeners binded. (not only the one you created before ) Commented Jun 29, 2015 at 12:26
  • 1
    it would be much easier for you to understand, just check the console jsfiddle.net/fvxo5tza/1 Commented Jun 29, 2015 at 12:28
  • 1
    Short: listener will be created every time and every listener will have it's own completeStatus variable, so just think that you have multiple subscribers. Commented Jun 29, 2015 at 12:30
  • 1
    Note in your question you have ++completeStatus, which produces 1 2 1 3 2 1, and in your fiddle you have completeStatus++, which produces 0 1 0 2 1 0. Commented Jun 29, 2015 at 12:44

4 Answers 4

2

Because you are using $(document).trigger('gt'); so it's initiating trigger event in all document event that's why increasing the call of function returning output like

0       //from first function call
1 0     //from second function call 
2 1 0   //frm third function call
.... and so on

Solution :

var test = function() {    
    var completeStatus = 0;
    var pageInitialized = false;    
    $(document).on('gt', function() {
        if(pageInitialized) return;
        console.log(++completeStatus);
        pageInitialized = true;
    });
    $(document).trigger('gt');
}

test();
test();
test();
Sign up to request clarification or add additional context in comments.

1 Comment

Works perfectly thanks! I can also unbind the event listener with $(document).off just after triggering it. So there's only one event listener at a given time.
2

.on() adds event listers, it doesn't replace previous ones:

Attach an event handler function for one or more events to the selected elements.

When an element has multiple event listeners, the order is well defined:

Event handlers bound to an element are called in the same order that they were bound.

And .trigger() executes them all in that order:

Execute all handlers and behaviors attached to the matched elements for the given event type.

Therefore,

  1. The first time you call test, you add an event listener with completeStatus = 0, and you trigger it. So you get

    0
    
  2. The second time you call test, the previous event listener has completeStatus = 1. Then you add a second event listener with completeStatus = 0, and you trigger both. So you get

    1 // From the first event listener
    0 // From the second event listener
    
  3. The third time you call test, the first event listener has completeStatus = 2, and the second one has completeStatus = 1. Then you add a third event listener with completeStatus = 0, and you trigger them all. So you get

    2 // From the first event listener
    1 // From the second event listener
    0 // From the third event listener
    

Comments

1

As mentioned in the above replies .on() adds event listener, so in your example its added 3 times.

In addition to the earlier answer it would be good to avoid adding multiple listeners as it could lead to memory leaks, if you fail to remove them. So you could try this solution which removes the event listeners before adding again.

var test = function() {    
   var completeStatus = 0;
   var GT_EVT = 'gt';

   $(document).off(GT_EVT).on(GT_EVT, function() {
      console.log(++completeStatus);
   });

   $(document).trigger(GT_EVT);

}

1 Comment

You're right to point out the performance matter. I also found out that it's possible and more straightforward to unbind the event handler from the inside of the listener itself: $(document).on('gt', function() { console.log(++completeStatus); $(document).off('gt'); });
0

An other way would be to generate unique events and handler each time the function is executed:

var test = function() {    
    var completeStatus = 0;
    var uniqid = Math.random().toString(36).slice(-8);

    $(document).on('gt' + uniqid, function() {
        console.log(++completeStatus);
    });
    $(document).trigger('gt' + uniqid);
}

test();
test();
test();

Fiddle

But what about performance implications? Is there any advantage/disadvantage using this approach?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.