jQuery延迟对象:.when()s,.then()和.done()s的意外行为

时间:2013-02-21 11:43:06

标签: javascript jquery jquery-deferred

我有一堆嵌套函数从ajax调用返回延迟对象。这是我的代码看起来像

function makeCalls() {
    var ajaxDfd1 = $.ajax(...);

    ajaxDfd1.then(function() {
        // want to execute after first call
        var ajaxDfd2 =  $.ajax(...);

        ajaxDfd2.done(function() {
            // want to execute after second call
        });

        return ajaxDfd2;
    });

    return ajaxDfd1;
}

makeCalls().done(function() {
    // stuff here was executed early
});

但我的电话没有按照我打算成为他们的顺序执行。似乎在makeCalls().done()实际完成之前调用ajaxDfd2内的东西。

3 个答案:

答案 0 :(得分:2)

Choc,

你在答案中做出了错误的假设;即$.ajax()返回“常规对象”。

这不正确。

$.ajax()返回一个jqXHR对象,它是Promise的超集,即。它具有Promise的所有方法以及其他特定于AJAX的方法(例如.abort())。

如果$.ajax()返回的对象不是Promise兼容的,那么问题中的代码会在尝试执行makeCalls().done(...)时出错。

首先执行.done()函数的原因是函数返回外部 jqXHR。

以下是实现您期望的行为的几种方法:

function makeCalls() {
    var dfrd = new Deferred();
    $.ajax(...).then(function() {
        $.ajax(...).done(dfrd.resolve);
    });
    return dfrd.promise();
}

makeCalls().done(function(data) {
    // ...
});

function makeCalls(fn) {
    $.ajax(...).then(function() {
        $.ajax(...).done(fn);
    });
}

makeCalls(function(data) {
    // ...
});

你甚至可以尝试:

function makeCalls() {
    return $.ajax(...).then(function() {
        return $.ajax(...);
    });
}

makeCalls().done(function() {
    // ...
});

答案 1 :(得分:0)

我知道我一定是弄错了,花了很长时间盯着这个: When should I use jQuery deferred's "then" method and when should I use the "pipe" method?

后来我意识到我做不到

var dfdObj = $.ajax(...);
dfdObj.then(...);

return dfdObj;

这实际上并不返回延迟对象。它返回一个Ajax对象,由于它是一个常规对象,它会自动归类为已解析,因此.done()函数被提前调用。相反,如果我想返回var

,我需要这样做
var dfdObj = $.ajax(...).then(...);

return dfdObj;

答案 2 :(得分:0)

您的代码的工作方式如下:

function makeCalls() {
    var ajax1 = $.ajax(…);
    var ajax1and2 = ajax1.then(makeCall2);
    function makeCall2() {
        // want to execute after first call
        var ajax2 =  $.ajax(…);
        ajax2.done(after2);
        function after2() {
            // want to execute after second call
        });
        return ajax2;
    });
    return ajax1;
}

var ajax1 = makeCalls();
ajax1.done(function() {
    // stuff here was executed early
});

ajax1and2是您想要的then / pipe电话的结果。对它的回调将等待等待makeCall2的{​​{1}}(即ajax2)的结果。它等于ajax1回调。

然而,您的after2函数会返回makeCalls对象(您可以看到我将其分配给全局ajax1变量)以及ajax1和已完成-callback将在你的第一个ajax完成后执行。

因此,您需要返回makeCall2延迟:

ajax1and2