使用 Ember 个具有定时队列排放的观察者

Using Ember observers with a timed queue drain

我正在尝试构建一个 "notification system" 类型的广播覆盖。本质上,我捕获事件,将它们添加到一个数组,然后我 运行 一个观察该数组的函数。每次添加事件时,我都会 运行 一个需要给定时间量的动画,将其从数组中删除,然后移动到下一个。

我发现 debounce 让我参与其中。我可以在动画播放时添加任意数量的事件 运行ning 并且它能够清空队列。

问题是,在处理第一个事件之前,我必须等待指定的时间(在本例中为 5 秒)。但是,当我将 debounce 设置为立即时,一切都会中断,因为第一个事件将被立即处理,但其他任何事件都不会。

# 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}."

我觉得我需要离开 debounce 来解决这个问题,但我不确定那个解决方案是什么。

如果您需要任何说明,请告诉我!

Ember.run.debounce

Ember.run.debounce 的目的是如果 debounce 在上次 X seconds 中没有被调用,则仅 运行 一次。

它的主要用途是在用户完成输入后启动某种类型的操作 - 因此对于有人输入的每个字符,您都可以调用 Ember.run.debounce(handleInput, 1000) 并且您可以确定,无论输入多少个字符每次他们按下一个键,你的功能只会 运行 一次 - 在他们没有按下一个键 1 秒之后。

它对于处理滚动事件也很有用 - 在页面上滚动时可以说有数百个滚动事件,但你只想在滚动停止后执行一些操作 - 调用 debounce 数百次在您停止为 timeout 值调用 debounce 之前,不会 运行 它(例如,在本例中的最后一个滚动事件后 100 毫秒)。

这似乎与您尝试做的有点不同。

建议的解决方案

我想你想做的是使用 Ember.run.later。您可以将它们全部组合成一个简单地观察 pool.firstObject 的函数 - 因为您总是在拉动第一个对象并在完成后将其删除。

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);

  }
})