如何将所有处理程序从一个延迟转移到另一个处理程序?

mpe*_*pen 9 jquery promise jquery-deferred

假设我有一个$.Deferred和一个jqXHR对象.有没有办法转移绑定到所有处理器的延迟(然后,一如既往地做,失败)到XHR对象(其中,按照我的理解,是延迟扩展)?


这就是我的想法:

$.ajaxOne = function(options) {
    var xhr = null;
    return function() {
        if(xhr) xhr.abort();
        xhr = $.ajax(options).always(function() {
            xhr = null;
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

我想创建一个类似的函数,$.ajax除非你快速连续多次调用它,它将中止最后一个请求并只完成最新的请求.要验证用户输入这是在许多情况下是有用的.

例如,您可能要检查,如果用户名取,但如果他们在用户名字段再次开始键入你开始你的Ajax调用后,你不关心最后的结果,只有最近的一个.

此外,我不认为请求保证按照它们发出的相同顺序返回(我想这取决于您的服务器设置),因此您也可能遇到同步问题.

无论如何,上面代码的问题是因为它返回一个函数,你可以随时执行你的ajax调用,但是你不能将你的完成处理程序绑定到它.所以我必须以某种方式混合延迟处理程序并将它们重新绑定到XHR对象.

mpe*_*pen 0

想出了这个:

function AjaxOne(options) {
    this.options = options;
    this._xhr = null;
    this._always = [];
    this._success = [];
    this._fail = [];
};

$.extend(AjaxOne.prototype, {
    always: function(cb) {
        this._always.push(cb);
        return this;
    },
    done: function(cb) {
        this._success.push(cb);
        return this;
    },
    fail: function(cb) {
        this._fail.push(cb);
        return this;
    },
    then: function(success, fail) {
        this._success.push(success);
        this._fail.push(fail);
        return this;
    },
    run: function(options) {
        if(this._xhr) {
            this._xhr.abort();
        }
        this._xhr = $.ajax($.extend({},options,this.options,{context:this}))
            .always(function() {
                this._xhr = null;
                for(var i=0; i<this._always.length;++i) this._always[i].apply(this,arguments);
            })
            .done(function() {
                for(var i=0; i<this._success.length;++i) this._success[i].apply(this,arguments);
            })
            .fail(function() {
                for(var i=0; i<this._fail.length;++i) this._fail[i].apply(this,arguments);
            });
    }
});
Run Code Online (Sandbox Code Playgroud)

到目前为止似乎工作得很好......但它没有回答我原来的问题。

因此,一个全面的答案是:您不能将回调从一个延迟复制到另一个。我尝试以各种方式制作延迟的副本,但$.extend({}, myDeferred)我无法让任何东西发挥作用。我认为您必须手动复制每个方法并触发适当的回调,类似于我所做的。

您可以将回调传播到原始延迟,正如 Arun 在他的评论中建议的那样(尽管我认为他的语法略有偏差;根据文档,您不需要.apply在那里;“with”方法的目的是允许你设置一个上下文)。就我而言,我希望能够多次触发这些方法,因此这不适用于我的场景。