【问题标题】:Deferred object returned before it is rejected or resolved?延迟对象在被拒绝或解决之前返回?
【发布时间】:2012-09-05 09:18:41
【问题描述】:

我有一个基本上看起来像这样的函数:

function defTest()
{
    var dfd = new jQuery.Deferred();
    $.ajax(
    {
        type: "GET",
        url: 'http://XXXX',
        cache: false,
        dataType: "json",
        success: function(data,status)
        {
            console.log('ajax done: success');
            dfd.resolve();
        },
        error: function(data,status)
        {
            console.log('ajax done: fail');
            dfd.reject();

        }
    });
    console.log('about to return dfd');
    return dfd;    
}

我这样称呼它:

defTest().then(.....);

控制台日志产生以下内容: 即将返回 dfd code.js:106 ajax 完成:成功 code.js:96

让我感到困惑的是代码似乎可以工作。仍然在 ajax 完成之前返回 dfd。所以我删除了return dfd。并将它放在每个 ajax 处理函数的最后,以确保在 Ajax 完成之前不会返回它。:

success: function(data,status)
{
    console.log('ajax done: success');
    dfd.resolve();
    return dfd;
}

然后它根本不起作用。我很迷惑!有人可以向我解释为什么我的 deferred 不能在 ajax 成功和错误处理程序中,为什么即使我的 deferred 对象在 Ajax 完成然后被解决或拒绝之前被触发,它似乎也返回了?这怎么可能?

编辑: 这个问题与我之前未回答且更复杂的功能直接相关: Problems with deferred object

这就是为什么我不能只“返回 ajax(...)”,因为我的真实函数包含其他 ajax 调用,这些调用将与一个返回给调用者的结果分开。

【问题讨论】:

  • XY problem。您无法从您的函数返回异步操作结果,这看起来就像您正在尝试做的那样。
  • 这就是我试图使用延迟对象解决的问题。
  • $.ajax 已经在 xdazz 回答时返回了一个延迟对象。 JavaScript 是单线程的,函数调用是同步的,并且必须同步返回一个值(或什么都不返回)。 $.ajax 是异步的。您可以(并且应该)做的是使用 ajax 成功回调来完成 ajax 请求完成后必须做的事情。
  • @Fabricio 感谢您的评论。但我不能只返回 ajax(),因为它不能解决我的问题……看看我在帖子中编辑的部分。

标签: jquery deferred


【解决方案1】:

$.ajax返回一个Deferred对象,所以只需要返回即可。

return $.ajax(...

【讨论】:

  • 是的,我知道。但我需要自己处理。该函数在我的真实代码中是更复杂的函数(多个 ajax 调用)。我需要知道为什么我的代码会这样。
【解决方案2】:

您对defTest 的调用将在您的ajax 调用开始 后立即返回。 它不会等到 deferred 解决与否。

但你完全可以做你想做的事:

defTest().then(function() { console.log("延迟完成"); })

当 deferred 最终解决时,它将打印deferred done

顺便说一句,正如 xdazz 所建议的那样,$.ajax 已经返回了 Deferred。

【讨论】:

【解决方案3】:

这样的问题很多
AJAX 请求本质上是 async,因此在第一个示例中,当您在最后一行返回它时。
它不需要等待 async ajax 完成
在第二种情况下,函数已经结束并且成功返回显然不会返回任何内容,因为您没有直接调用分配给 success 事件的方法
更新:- 在评论之后
因为在返回 deffered 对象后你正在做 defTest().then(.....);
所以当 deffered 对象被解析时, then 处理程序中的函数显然会被触发。
可能您应该在返回 deffered 对象后立即检查它的值,而不是使用 .then(),您会发现您在这里犯了什么错误
更新 2 -
看看这里http://jsfiddle.net/BtEKa/我得到了可预测的结果

【讨论】:

  • 但在我的第一种情况下,似乎返回已解决或被拒绝的对象似乎有效。因为即使 console.log 看起来有问题。我每次都能得到完美的结果。这怎么可能?
  • 谢谢 Parv Sharma。但它有效。即使日志说别的。最后使用 return dfd 。调用者成功或失败事件将被触发。但是这怎么可能,因为它看起来(根据console.log,在实际的ajax语句完成并使dfd解析或拒绝之前触发了返回dfd。这怎么可能?逻辑应该是dfd会返回“待定”状态,因为它在被拒绝或解决之前被退回。这让我有点毛骨悚然,因为我不明白这是怎么回事。
  • 看看这个:jsfiddle.net/BtEKa/9 我的猜测是因为我使用了 alert() ajax 有时间完成或类似的事情。所以回到第 1 步。我如何确保我会根据函数向调用者获得成功或失败的结果?
  • 如果你能这样做,这个问题就会得到解决:jsfiddle.net/2GVbA/1 但是你不能运行 return dfd;出于某种原因。
【解决方案4】:

当然,它会立即返回,这就是重点。通常,一种方法是返回延迟对象的承诺成员——尽管您可以返回延迟对象并在调用此函数的代码中使用 returnedDeferredObject.promise().then()。

如果您有依赖于 AJAX 完成的处理,则该处理将在返回的 .promise() 的 .then() 函数中进行。美妙之处在于,在进行异步处理的同时,您可以执行不依赖于 AJAX 返回的其他事情。您可以将返回的 .promise() 传递给其他代码。

var mydata = somethingThatReturnsPromise(args);

// do a whole bunch of things

mydata.then(function (returnedReponse) {
    // do stuff with returnedResponse that doesn't require DOM ready
});

$(function () {
    mydata.then(function (returnedResponse) {
        // do DOM stuff with returnedPromise
    });
});

我希望我没有错过你的观点,但我喜欢将返回的 Promise 视为我可以在以后一次又一次地使用的数据源,并且我指定的 .then() 回调只会执行一次有一个返回的响应。

作为旁注,我很确定随着 jQuery 更接近承诺标准,.done()、.pipe()、.fail() 和 .progress() 应该被替换为 .then( successCb、failCb、progressCb)。

【讨论】:

    【解决方案5】:

    我相信您的问题是您返回的是整个延迟对象,而不是该对象的承诺。

    承诺 afiak 总是在异步调用返回之前返回,所以虽然你的最后一个 console.log 将在返回 PROMISE 之前触发,但它会在 ajax 解决之前发生。

    使用 .then() 也可能不是您想要的,因为无论延迟对象的状态如何,它都会触发:http://api.jquery.com/deferred.then/

    你可能想要 .done()

    试试这个:

    function defTest()
    {
        var dfd = $.Deferred();
        $.getJSON("http://XXXX").done(function(data,success){
          console.log('ajax done: success');
          dfd.resolve(data);
        }).fail( function(data,status) {
          console.log('ajax done: fail');
          dfd.reject();
        });
        console.log('about to return dfds promise');
        return dfd.promise;    
    }
    defTest().done(function(data){ console.log(data); });
    

    【讨论】:

      猜你喜欢
      • 2015-05-01
      • 2011-08-15
      • 1970-01-01
      • 1970-01-01
      • 2015-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多