如果这是一个愚蠢的问题,请原谅我。我已经尝试了几个小时,而我的大脑却刚刚停止工作。

我有这样的系统,它包含三个AJAX调用。服务器首次 call 的响应通常为200成功;但是第二个和第三个查询是脆弱的,因为它们是图像上传,并且在服务器端,我有太多的验证规则,因此客户端的图像大多会失败。

window.AjaxCall = function () {
    // to pass to $.ajax call later
    this.args = arguments;

    // xhr status
    this.status = null;

    // xhr results (jqXHR object and response)
    this.xhrResponse = {};

    this.dfr = new $.Deferred();

    // to provide an easier interface
    this.done = this.dfr.done;
    this.fail = this.dfr.fail;
    this.then = this.dfr.then;
};

AjaxCall.prototype.resetDfr = function () {
    this.dfr = new $.Deferred();
};

AjaxCall.prototype.resolve = function () {
    this.dfr.resolve(
            this.xhrResponse.result,
            this.xhrResponse.jqXHR
    );

    this.resetDfr();
};

AjaxCall.prototype.reject = function () {
    this.dfr.reject(
            this.xhrResponse.jqXHR
    );

    this.resetDfr();
};

AjaxCall.prototype.query = function () {
    var _this = this;

    // if query hasn't run yet, or didn't return success, run it again
    if (_this.status != 'OK') {
        $.ajax.apply(_this, _this.args)
                .done(function (result, textStatus, jqXHR) {
                    _this.xhrResponse.result = result;
                    _this.xhrResponse.jqXHR = jqXHR;
                    _this.resolve();
                })
                .fail(function (jqXHR) {
                    _this.xhrResponse.jqXHR = jqXHR;
                    _this.reject();
                })
                .always(function (a, b, c) {
                    var statusCode = (typeof c !== 'string'
                            ? c
                            : a).status;

                    if (statusCode == 200) {
                        _this.status = 'OK';
                    }
                });
    }

    // if query has been run successfully before, just skip to next
    else {
        _this.resolve();
    }

    return _this.dfr.promise();
};
AjaxCall类如上所述,并且我进行了三个连续的调用,如下所示:
var First = new AjaxCall('/'),
        Second = new AjaxCall('/asd'),
        Third = new AjaxCall('/qqq');

First.then(function () {
    console.log('#1 done');
}, function() {
    console.error('#1 fail');
});

Second.then(function () {
    console.log('#2 done');
}, function() {
    console.error('#2 fail');
});

Third.then(function () {
    console.log('#3 done');
}, function() {
    console.error('#3 fail');
});

var toRun = function () {
    First.query()
            .then(function () {
                return Second.query();
            })
            .then(function () {
                return Third.query()
            });
};

$('button').click(function () {
    toRun();
});

这些代码在测试环境中。通过测试环境,我的意思是简单的HTML页面和用于调试的基本服务器支持。
  • 主页(/)始终返回200成功。
  • / asd会在前3次和200成功一次中将作为模式返回404 Not Found(即三个404->一个200->三个404s->一个200->三个404s-> ...)。
  • / qqq始终返回404 Not Found。

  • 当我单击页面上的唯一按钮时,第一个查询返回成功,第二个查询按预期失败。当我第二次单击该按钮时,第一个查询将跳过,因为上次成功,第二次再次失败,这也是预期的。

    这里的问题是:

    我使用resetDfr方法
    之前的
  • ,因为dfr可以解析或拒绝,但它不再对resolvereject方法作出反应。
  • 当我以示例所示的方式调用resetDfr方法时,dfr可以再次得到解决或拒绝,但是旧dfr的回调未与新的dfr对象绑定(bind),并且我找不到将旧的回调克隆到新的dfr的方法。

  • 您对我在这里想要完成的工作有何建议?

    最佳答案

    promise 表示受时间限制的单个值。从概念上讲,您不能“重用”或推迟重设-一旦过渡,它便会停留。有些构造将对多个值的 promise 概括化(例如可观察到的),但是在这种情况下,它们会更复杂-每个请求只使用一个延迟的构造可能会更好。

    jQuery的AJAX已经提供了promise接口(interface)。您的代码大部分都是多余的-您可以并且应该考虑使用现有的工具。

    让我们看看$.get:

  • 它已经返回了promise,因此您无需创建自己的延期。
  • 它已经使用了浏览器缓存,除非您的服务器禁止HTTP缓存或浏览器拒绝它,否则在正确的响应到达后仅向服务器发出一个请求(假定您未将{cache: false}明确传递给其参数。

  • 如果发出发布请求,则可以将$.post或更常见的$.ajax用于任意选项。

    这是您的代码大致如下所示:
    $("button").click(function(){
        var first = $.get("/");
        var second = first.then(function(){
           return $.get("/asd");
        });
        var third = second.then(function(){
           return $.get("/qqq");
        });
    });
    

    我将它们放在变量中的原因是,这样您以后就可以通过执行first.then等来解开结果。也很可能也可以在单个链中执行此操作(但是,如果您未明确指定,则无法访问以前的值)保存。

    记录下来-这根本不是一个愚蠢的问题:)

    09-25 18:49