5

我希望能够使用 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
});

当然,由于 filter 返回一个数组,所以 done 回调是用一个数组调用的,而不是枚举的参数。据我所知,管道只能修改提供的参数,不能添加。任何建议,将不胜感激。

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

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

4

2 回答 2

2

我发现我可以通过让 .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);
};
于 2012-10-25T17:10:18.010 回答
1

一个与您的答案非常相似的解决方案,但没有管道,因为您实际上不需要过滤结果:我直接从 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/

于 2012-10-25T17:46:27.600 回答