Backbone.js - 在上一次保存之前保存模型时出现问题POST(创建)而不是PUT(更新)请求

Mat*_*dan 15 javascript ajax backbone.js

我使用Backbone.js开发了一个很好的丰富的应用程序界面,用户可以非常快速地添加对象,然后通过简单地选项到相关字段来开始更新这些对象的属性.我遇到的问题是,有时用户将服务器击败到其初始保存,我们最终保存了两个对象.

如何重新创建此问题的示例如下:

  1. 用户单击添加人员按钮,我们将其添加到DOM但不保存任何内容,因为我们还没有任何数据.

    person = new Person();

  2. 用户在"名称"字段中输入一个值,并从中输出选项卡(名称字段失去焦点).这会触发保存,以便我们更新服务器上的模型.由于模型是新的,Backbone.js将自动向服务器发出POST(创建)请求.

    person.set ({ name: 'John' });

    person.save(); // create new model

  3. 然后,用户可以非常快速地键入他们已选中的年龄字段,输入20并将标签输入到下一个字段(因此年龄失去焦点).这再次触发保存,以便我们更新服务器上的模型.

    person.set ({ age: 20 });

    person.save(); // update the model

因此,在这种情况下,我们期望一个POST请求创建模型,一个PUT请求更新模型.

但是,如果第一个请求仍在处理中,并且我们在上面第3点的代码运行之前没有响应,那么我们实际获得的是两个POST请求,因此创建了两个对象而不是一个.

所以我的问题是,是否有一些最佳实践方法来处理这个问题和Backbone.js?或者,Backbone.js是否应该有一个用于保存操作的排队系统,以便在该对象的上一个请求成功/失败之前不会发送一个请求?或者,或者我应该通过仅发送一个创建请求而不是多个更新请求来构建一些优雅地处理它的东西,可能使用某种类型的限制,或者检查Backbone模型是否在请求的中间并等待该请求是完成.

您对如何处理此问题的建议将不胜感激.

我很高兴能够实现某种排队系统,尽管你可能需要忍受我的代码,这些代码不会像现有的代码库一样好!

Mat*_*dan 9

我已经测试并设计了一个补丁解决方案,受到@Paul和@Julien的启发,他们发布了这个帖子.这是代码:

(function() {
  function proxyAjaxEvent(event, options, dit) {
    var eventCallback = options[event];
    options[event] = function() {
      // check if callback for event exists and if so pass on request
      if (eventCallback) { eventCallback(arguments) }
      dit.processQueue(); // move onto next save request in the queue
    }
  }
  Backbone.Model.prototype._save = Backbone.Model.prototype.save;
  Backbone.Model.prototype.save = function( attrs, options ) {
    if (!options) { options = {}; }
    if (this.saving) {
      this.saveQueue = this.saveQueue || new Array();
      this.saveQueue.push({ attrs: _.extend({}, this.attributes, attrs), options: options });
    } else {
      this.saving = true;
      proxyAjaxEvent('success', options, this);
      proxyAjaxEvent('error', options, this);
      Backbone.Model.prototype._save.call( this, attrs, options );
    }
  }
  Backbone.Model.prototype.processQueue = function() {
    if (this.saveQueue && this.saveQueue.length) {
      var saveArgs = this.saveQueue.shift();
      proxyAjaxEvent('success', saveArgs.options, this);
      proxyAjaxEvent('error', saveArgs.options, this);
      Backbone.Model.prototype._save.call( this, saveArgs.attrs, saveArgs.options );
    } else {
      this.saving = false;
    }
  }
})();
Run Code Online (Sandbox Code Playgroud)

其工作原理如下:

  1. 当仍在执行模型上的更新或创建请求方法时,下一个请求将被放入队列中,以便在调用其中一个错误或成功的回调时进行处理.

  2. 请求时的属性存储在属性数组中并传递给下一个保存请求.因此,这意味着当服务器使用第一个请求的更新模型进行响应时,排队请求中的更新属性不会丢失.

我上传了一个可以在这里分叉Gist.


Pau*_*aul 5

一个轻量级的解决方案是修补Backbone.Model.save,所以你只会尝试创建一次模型; 应该延迟任何进一步的保存,直到模型具有id.这样的东西应该有效吗?

Backbone.Model.prototype._save = Backbone.Model.prototype.save;
Backbone.Model.prototype.save = function( attrs, options ) {
    if ( this.isNew() && this.request ) {
        var dit = this, args = arguments;
        $.when( this.request ).always( function() {
            Backbone.Model.prototype._save.apply( dit, args );
        } );
    }
    else {
        this.request = Backbone.Model.prototype._save.apply( this, arguments );
    }
};
Run Code Online (Sandbox Code Playgroud)