检查例如文件上载的动态延迟量

时间:2013-11-28 20:53:26

标签: backbone.js marionette jquery-deferred

上下文

情况如下:用户可以在应用程序中上传文件。他们可以随时(和次数)这样做。

我想在完成任何上传时显示一个微调器,并在当前没有上传时将其删除。

我的方法

上传是外部文件上传插件(如blueimp)的处理,在它的添加方法上我抓住jqXHR对象并将它们添加到主干集合(这是我的应用程序中的图像,所以我将它与Marionette的组合使用collectionviews)。

以下是在Marionette Itemview的onRender回调中调用的函数的一部分:

// Get the file collection
var uploadFiles = SomeBackBoneCollection;

// Track how many deferreds are expected to finish
var expected = 0;

// When an image is added, get the jqXHR object
uploadFiles.bind('add', function(model) {
    // Get jqXHR object and call function which tracks it
    trackUploads(model.get('jqXHR'));

    // Do something to show the spinner
    console.log('start the spinner!');

    // Track amount of active deferreds
    expected++;
}, this);

// Track the uploads
function trackUploads(jqXHR) {
    $.when(jqXHR).done(function(){
        // A deferred has resolved, subtract it
        expected--;

        // If we have no more active requests, remove the spinner
        if (expected === 0) {
            console.log('disable the spinner!');
        }
    });
}

讨论

这种方法效果很好,虽然我想知道是否还有其他(更好的)方法。

您如何看待这种方法?关于这种方法,你看到任何上行或下行吗?有人提出任何其他方法或建议吗?

例如,拥有一些可以继续传递延迟的数组/对象可能会很棒,并且$ .when以某种方式监视此集合并在任何时候完成所有操作后解析。但是,这应该可以使您在任何给定时间都可以继续传递延迟对象。

1 个答案:

答案 0 :(得分:0)

你可以通过活动来做到这一点。

我假设每个文件都是此模型的一个实例:

App.Models.File = Backbone.Model.extend({});

在用户上传文件之前,您实际上是在创建一个新模型并保存它。

uploadedFiles.create(new App.Models.File({...}));

所以在你的上传视图中......

//listen to collection events
initialize: function() {
  //'request' is triggered when an ajax request is sent
  this.listenTo(this.collection, 'request', this.renderSpinner);
  //when the model is saved, sync will be triggered
  this.listenTo(this.collection, 'sync', this.handleCollectionSync);
}

renderSpinner: function() {
  //show the spinner if it is not already being shown.
}

好吧,所以,在'handleCollectionSync'函数中,你想决定我们是否想要隐藏微调器。 那么我们怎么知道是否还有上传的模型?检查集合中是否有新模型(未保存的模型)

所以在你的集合中,添加一个帮助方法:

 App.Collections.Files = Backbone.Collection.extend({

   //if there's a new model, return true
   hasUnsavedModels: function() {
     return this.filter(function(model) {
       return model.isNew();
     }).length > 0;
   }
 });

回到你的观点:

 handleCollectionSync: function() {
   //if there's no unsaved models
   if(!this.collection.hasUnsavedModels()){
     //removespinner
   }
 }

这可以解决您的问题,假设所有上传成功。您可能希望通过错误处理案例完成此操作 - 这取决于您对错误案例的处理方式,但只要您不立即重试,就应该将其从集合中删除。

=============================================== ===========================================

修改

我在想,如果您允许用户多次上传文件,您实际上并不是在创建新模型,而是更新现有模型,因此之前的答案无效。为了解决这个问题,我会跟踪模型本身的状态。

App.Models.File = Backbone.Model.extend({
  initialize: function() {
    this.uploading = false; //default state
    this.on('request', this.setUploading);
    this.on('sync error', this.clearUploading);
  }
});

然后setUploading方法应该设置为true,clearUploading应该将其更改为false;

并在您的收藏中:

hasUnsavedModels: function() {
  return this.filter(function(model) {
    return model.uploading;
  }).length > 0;
}

所以在您看来,当您创建新文件

uploadNewFile: function(fileAttributes) {
  var newFile = new App.Model.File(fileAttributes);
  this.collection.add(newFile);
  newFile.save();
}

我相信当你在其中保存模型时,也会在集合上触发'sync'和'request'事件。因此,您仍然可以在视图中收听集合上的请求,同步和错误事件。