【问题标题】:Jquery Deferred() upload progressJquery Deferred() 上传进度
【发布时间】:2013-04-28 09:49:14
【问题描述】:

有没有人有关于如何从 $.Deferred() 获取上传进度的示例?我想像您使用 XHR.onprogress 一样收听进度事件

上下文: 使用backbone.js 我想做这样的事情。保存模型后,我正在上传一个中等大小的 base64 编码图像。

var def = model.save();
def.progress(function(value){
    console.log(value);
});

【问题讨论】:

  • jQuery 插件 ajaxForm 会有所帮助。你会发现它有一个uploadProgress 选项,它允许通过回调函数来监控进度。文档包括附带条件,“如果浏览器支持”。

标签: backbone.js jquery-deferred jqxhr


【解决方案1】:

这很棘手,我不确定我的代码是否有效,只是给你一个基本的想法。您必须修改 model.savedo it globally for all $.ajax calls 中的 ajax 选项。

这也不会进入延迟,您必须使用进度回调。从修补 ajax 选项的链接中包含 js 后,您将能够使用进度回调:

model.save({}, {

    progress: function(e) {
        //make sure we can compute the length
        if(e.lengthComputable) {
            //calculate the percentage loaded
            var pct = (e.loaded / e.total) * 100;

            //log percentage loaded
            console.log(pct);
        }
        //this usually happens when Content-Length isn't set
        else {
            console.warn('Content Length not reported!');
        }
    }

})

另一种选择是修补Model.sync

ProgressModel = Backbone.Model.extend({

    sync: function(method, model, options) {

        function progress(e) {
            model.trigger('progress', e)
        }

        var newOptions = _.defaults({
            xhr: function() {
                var xhr = $.ajaxSettings.xhr();
                if(xhr instanceof window.XMLHttpRequest) {
                    xhr.addEventListener('progress', progress, false);
                }
                if(xhr.upload) {
                    xhr.upload.addEventListener('progress', progress, false);
                }
                return xhr;
            }
        }, options);

        return Backbone.sync.call(this, method, model, newOptions); 
    }

});

// so now you can listen to progress event on model
model.on('progress', function(e) { })
model.save();

【讨论】:

  • 为什么你有 xhr.addEventListenerxhr.upload.addEventListener ?因此,与进度事件关联的回调会被触发两次。
【解决方案2】:

我决定只在模型上创建一个单独的方法,因为我只需要监控 POST 请求的进度。在我的收藏中,作为“添加”处理程序,我做了:

onAdd: function (model) {
        var xhr = new XMLHttpRequest();
        var $def = $.Deferred();

        this.uploadQueue.push($def.promise());

        xhr.open('POST', 'http://myapi/upload-image', true);

        xhr.upload.onprogress = function(e) {
            if (e.lengthComputable) {           
              console.log((e.loaded / e.total) * 100);
            }
        }

        xhr.onload = function(e) {
            if (this.status == 201) {
              console.log(this.responseText);
              $def.resolve();
            }
        };

        xhr.send(JSON.stringify(model.toJSON()));

    }

稍后在我的代码中,我可以检查 collection.uploadQueue 是否已完成以执行其他操作。似乎目前正在满足我的需求。

【讨论】:

  • 我不会采用这种方法,因为它不平静并且违反了骨干原则。为什么选择发出单独的 ajax 请求而不使用 Backbone.sync?您的模型在发布后不会更新,也不会触发任何事件。
  • 此“图像列表”仅用于另一个模型(位置)的“创建”形式。我不需要使用这个模型更新、读取或删除,所以我认为覆盖同步是多余的,我没有时间学习如何最小化覆盖同步。我为照片创建了一个单独的模型和集合,这样我就可以管理屏幕上的列表并在用户选择它们时乐观地上传图像。这减少了用户实际提交整个表单时的感知等待时间。话虽如此,我确实喜欢你的建议,我会在重构代码时尝试实现它。再次感谢。
  • 好的,祝你的项目好运。关于文件上传,您可以查看我的这个答案:stackoverflow.com/a/16275792/329226 我使用 Formdata 发布具有文件属性的模型。
猜你喜欢
  • 1970-01-01
  • 2011-06-18
  • 1970-01-01
相关资源
最近更新 更多