0

I'm attempting to build a "notification system" of sorts for a broadcasting overlay. Essentially I catch events, add them to an array, then I run a function that observes that array. Each time an event is added, I run an animation that takes a given amount of time, remove that from the array and then move onto the next one.

I found that debounce gets me a part of the way there. I'm able to add any number of events while the animations are running and it's able to empty the queue.

Problem being, I have to wait that specified time (in this case 5 seconds) before the first event is handled. However, when I set debounce to be immediate, everything breaks in that the first event will be immediately handled, but nothing else will.

# Pool handling.
pool: []

# Function adds events to the pool array.
addEventToPool: (event, data) ->
  console.log "added #{event} with #{data} to pool!"
  @get('pool').pushObject(data)

# Function that observes the pool array and runs debounce 
# if there are any items in the pool.
observePool: (->
  Ember.run.debounce(@, @handleEvent, 5000, false) if @get('pool').length
).observes('pool.[]')

# Event handling.
handleEvent: ->
  pool = @get('pool')
  object = pool.get('firstObject')
  @set('payload', object)

  Ember.$(".event-message__#{object.event}").addClass('active')

  Ember.run.later (->
    Ember.$(".event-message__#{object.event}").removeClass('active')
    pool.removeObject(object)
  ), 2000

  console.log "Number of remaining objects: #{pool.length}."
  console.log "Objects remaining: #{JSON.stringify pool}."

I have a feeling that I need to move off of debounce to fix this, but I'm not sure what that solution is.

Please let me know if you need any clarification!

Bryan Veloso
  • 1,595
  • 18
  • 34
  • With the first event, are you wanting to handle that instantly or do you want to wait for 5 seconds on the initial event? Or you don't care? And secondly, lets say you get two events which are handled at 10:30:10 then 10:30:15 - if your third event comes in at 10:30:22 (which is 7 seconds after the second event) - do you want to handle that right away (at 10:30:22), or do you want to wait an additional 5 seconds (at 10:30:27)? – jmurphyau Apr 22 '15 at 22:34
  • I want to handle the first event instantly. If a third event comes at 10:30:22, which is after the second event, the pool would be empty hypothetically, so I'd want to handle that right away. – Bryan Veloso Apr 22 '15 at 23:12

1 Answers1

3

Ember.run.debounce

The purpose of Ember.run.debounce is to only run something once if debounce has not been called in the last X seconds.

It's main uses are for things like kicking off some type of action after a user has finished typing - so on every character someone is typing you could call Ember.run.debounce(handleInput, 1000) and you can be sure that no matter how many times they press a key, your function will only run once - after they haven't pressed a key for 1 second.

It's also useful for handling scroll events - where there are lets say hundreds of scroll events when scrolling on a page but you only want to do some action once the scrolling has stopped - calling debounce hundreds of times doesn't run it until you've stopped calling debounce for the timeout value (e.g. 100ms after the last scroll event in this case).

This seems a little bit different to what you're trying to do.

Suggested Solution

I think what you want to do is use Ember.run.later. You could combine it all into one function that simply observes pool.firstObject - since you're always pulling the first object and removing it once you're done.

handleEvent: Ember.observer('pool.firstObject', function() {
  var pool = this.get('pool');
  var obj = pool.get('firstObject');
  if (obj) {
    // add class
    Ember.$(".event-message__#{object.event}").addClass('active');

    // schedule remove class for 2 seconds from now
    Ember.run.later(function() {
      Ember.$(".event-message__#{object.event}").removeClass('active');
    }, 2000);

    // schedule remove object from pool 5 seconds from now
    Ember.run.later(function() {
      pool.removeObject(obj);
      // after you've removed this object (which was firstObject)
      // pool.firstObject will change, and the handleEvent function 
      // will get kicked off again
    }, 5000);

  }
})
jmurphyau
  • 2,309
  • 13
  • 11