【问题标题】:Can I use jQuery's deferred.pipe method to modify arguments supplied to resolved/fail callbacks?我可以使用 jQuery 的 deferred.pipe 方法来修改提供给已解决/失败回调的参数吗?
【发布时间】:2012-10-25 16:33:46
【问题描述】:

我希望能够使用 jQuery 的 Deferred 对象通过 Backbone 集合和模型来操作加载数据。有什么方法可以修改提供给 done 和 fail 回调的参数以包含 Model 或 Collection 实例?我的设想如下:

var _sync = Backbone.sync;

Backbone.sync = function() {
    var jqXhr = _sync.apply(this, arguments);

    var self = this;
    return jqXhr.pipe(function() {
        var cbArgs = [self];
        cbArgs.push.apply(cbArgs, arguments);
        return cbArgs; 
    }
}

...
var c = new Backbone.Collection();
c.url = "/path/to/resources";
c.fetch().then(function(collection, data, textStatus, jqXhr) {
    // do stuff with collection
});

当然,因为过滤器返回一个数组,所以完成回调是用一个数组调用的,而不是枚举的参数。据我所知,管道只能修改提供的参数,不能添加。任何建议将不胜感激。

编辑:这是一个非常简单的例子;由于在原始集合上创建了一个闭包,因此我可以对其进行操作。但是,用例是多个 Backbone 视图可能依赖于获取的相同数据,所以我希望能够只为这些视图提供 jQuery Deferred 对象,而不是 Deferred 和集合实例。

另一个编辑:在下面发布了一个解决方案,但欢迎任何其他建议。

【问题讨论】:

    标签: javascript jquery backbone.js jquery-deferred


    【解决方案1】:

    我发现我可以通过让 .pipe 方法返回一个新的 $.Deferred 来实现这一点,该 $.Deferred 可以使用修改后的参数立即解决:

    var _sync = Backbone.sync;
    
    Backbone.sync = function() {
        var jqXhr = _sync.apply(this, arguments);
    
        var self = this;
        var deferred = jqXhr.pipe(function() {
            var cbArgs = [self];
            cbArgs.push.apply(cbArgs, arguments);
            var deferred = new $.Deferred();
            return deferred.resolve.apply(deferred, cbArgs);
        });
        return $.extend(true, jqXhr, deferred);
    };
    

    【讨论】:

    • 已编辑以使用新的 $.Deferred 扩展原始 jqXhr,保持对所有 AJAX 特定方法(.success、.abort 等)的支持。
    【解决方案2】:

    一个与您的答案非常相似的解决方案,但没有管道,因为您实际上不需要过滤结果:我直接从 Backbone.sync 返回一个新的延迟,而不是管道一个已解决的延迟

    Backbone.originalSync = Backbone.sync;
    Backbone.sync = function(method, model, options) {
        var xhr = Backbone.originalSync.call(this, method, model, options);
    
        var dfd = $.Deferred();
        xhr.done(function() {
            var cbArgs = [model].concat(_.toArray(arguments));
            dfd.resolve.apply(dfd, cbArgs);
        });
        xhr.fail(function() {
            var cbArgs = [model].concat(_.toArray(arguments));
            dfd.reject.apply(dfd, cbArgs);
        });
    
        return dfd;
    };
    

    还有一个小提琴http://jsfiddle.net/d8FqA/

    如果您愿意将 this 绑定到回调中的模型/集合,则可以使用更简单的变体,这样函数签名不会受到影响:

    Backbone.originalSync = Backbone.sync;
    Backbone.sync = function(method, model, options) {
        var xhr = Backbone.originalSync.call(this, method, model, options);
    
        var dfd = $.Deferred();
        xhr.done(function() {
            dfd.resolveWith(model, arguments);
        });
        xhr.fail(function() {
            dfd.rejectWith(model, arguments);
        });
    
        return dfd;
    };
    
    var c=new Backbone.Collection();
    c.fetch().done(function() {
        console.log(this);
        console.log(arguments);
    });
    

    http://jsfiddle.net/d8FqA/1/

    这导致我们将模型作为上下文传递给 Ajax 请求:

    Backbone.originalSync = Backbone.sync;
    Backbone.sync = function(method, model, options) {
        options || (options={}) ;
        options.context = model;
        return Backbone.originalSync.call(this, method, model, options);
    };
    
    var c=new Backbone.Collection();
    c.fetch().done(function() {
        console.log(this);
    });
    

    http://jsfiddle.net/d8FqA/2/

    【讨论】:

    • 有趣...绝对是类似的解决方案。我认为这两种解决方案都可以从中受益的一件事是使用新的延迟扩展原始 jqXhr 对象,这样来自 Backbone.sync 的响应根本不会改变(承诺除外)例如)返回 $.extend(真,xhr,dfd);
    • @philm 我认为我们可以通过在回调中使用上下文来简化很多事情,并且不理会 xhr 对象。用解决方案更新了我的答案
    • 这里提出的一个问题是,如果我们正在等待解决多个 deferred,那么上下文将绑定到哪个集合?例如:) var col1 = new Bacbkone.Collection(), col2 = new Backbone.Collection(); $.when(col1.fetch(), col2.fetch()).then(function() { ... });
    • 似乎是一种聚合上下文的奇怪模式......鉴于等待多个异步操作是我们一直试图解决的常见模式,我更倾向于提供模型/集合作为函数参数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-24
    • 1970-01-01
    • 1970-01-01
    • 2012-09-04
    • 2020-08-01
    • 1970-01-01
    • 2012-12-08
    相关资源
    最近更新 更多