Ember 自动保存 - 排队保存请求

Ember Auto-save - queueing save requests

例如,用户在文本框内不断按下某个键,并向服务器发送保存请求以保存该值。

通过去抖动来推迟后续事件是行不通的,因为每个 keyUp 都是 运行 在一个新的 运行 循环中,这与长时间按住按键并以这种方式输入字符不同。

所以问题是:最 Ember 方法 A) 在发送新请求之前等待请求完成,以确保旧值不会覆盖新值,以及 B ) 确保至少发送最后一个请求,保存最新的用户输入值。

更新:

在四处寻找之后,似乎我最初错过了一件重要的事情,这导致我每次按下一个键都会保存 运行,而不是每个去抖动期一次,是传递给 debounce 方法的函数必须命名。分解出保存代码并将引用传递给函数可以在 2 秒间隔内最多保存一次。

  keyUp: function(e) {
    Ember.run.debounce(this, this.saveFieldValue, 2000);
  },
    
  saveFieldValue: function() {
    const field = this.get('field');
    field.save();
  },

UPDATE2:@nem035 下面的回答解决了我的其他要求:排队保存,因此不会丢失任何内容。去抖有效但不能保证。

如果您不关心被忽略的事件,您消除事件抖动的方法是最 Ember 的方法,并且可能是最适合您的方法,但这里有一些可能的替代方法:

简单方法(忽略额外事件)

你可以做的一件简单的事情就是有一个标志,初始化为 false,在操作开始之前设置为 true 并在操作开始时重置回 false完成。

saveFieldValue: function() {
  if (!this.get('isSaving')) {

    const field = this.get('field');

    this.set('isSaving', true);
    field.save().then(() => {
      this.set('isSaving', false);
    });
  }
}

这类似于您的去抖动方法(忽略额外的事件),但我们有一个标志,如果先前的操作尚未完成,则可以防止操作发生。拥有一个标志还可以帮助您在保存数据时显示微调器或禁用在保存期间无法使用的按钮或类似的东西。


复杂的方法(额外的事件排队)

如果您不希望任何事件在保存数据时发生 swallowed/ignored 而是希望所有事件都发生(最终),您可以做的另一件事是创建您自己的事件队列通过将保存事件排队并运行一个接一个地按顺序处理它们。

此外,您必须处理队列在一段时间后重新检查自身的情况,以 运行 在此期间可能已经排队的任何任务。

这是一个使用数组作为队列的简单演示:

// ...

queue: null,

init() {
  this._super(...arguments);

  // ...

  // initialize a new queue for each instance
  this.set('queue', Ember.A()); 

  // start the queue process
  this.processQueue();
},

processQueue() {
  const queue = this.get('queue');

  // if the queue is empty, try again in 100ms (this value is arbitrary, see what would work best for you)
  if (Ember.isEmpty(queue)) {
    Ember.run.later(this, this.processQueue, 100);
  } 

  // otherwise remove the oldest field
  // save it
  // and then re-run the queue process
  else {
    // remove and save the oldest-first
    queue.shiftObject().save()
      .then(() => {
        // here we can do success handling for the saved field
      }, () => {
        // here we can do error handling for the saved field
      })
      .then(() => {
        this.processQueue();
      });
  }
},

saveFieldValue: function() {
  const {
    field, queue
  } = this.getProperties('field', 'queue');

  // push the current field value to the queue 
  queue.pushObject(field);
}

这是一个 EmberTwiddle 示例