jQuery.when的理解

70

我试图使用jQuery.when来触发两个ajax请求,然后在这两个请求都完成后调用一些函数。以下是我的代码:

var count = 0;
var dfr;

var showData = function(data) {
    dfr.resolve();
    alert(count);
   // Do something with my data data received
};

var method1 = function() {
    dfr = $.Deferred();

    return $.ajax('localhost/MyDataService/DataMethod_ReturnsData', {
        dataType: "jsonp",
        jsonp: "$callback",
        success: showData
    });
};

var method2 = function() {
    return $.ajax('localhost/MyDataService/DataMethod_ReturnsCount', {
        dataType: "jsonp",
        jsonp: "$callback",
        success: function(data) {
            count = data.d.__count;
        }
    });
};

$.when(method1(), method2())
    .then(showData());
但是,这并没有按预期工作。在method1中的Ajax调用将返回要在showData()中使用的数据,而在method2中的Ajax调用将返回要分配给变量计数的计数,并稍后在showData()中使用。但是当我执行上面的代码时,method1被调用,然后是method2,然后是showData,使得showData中的数据为'undefined'。我如何通过$.when实现这一点,只有在返回$.promise的两个函数都执行时才会进行,据我所知。我希望两个ajax调用应该并行调用,稍后根据两个调用的结果显示结果。

你根本不需要 dfr = $.Deferred(),因为 $.ajax() 返回的 jqXhr 已经是一个 deferred。不确定这是否会解决问题,但这绝对是不必要的。问题可能是你使用了 .then() 而不是 .done() - Matt Ball
我指的是Eric Hynds的这篇帖子[http://www.erichynds.com/jquery/using-deferreds-in-jquery/],他也使用了$.when和then回调函数。 - Ashish
1
只有在你使用的对象不能直接处理"deferred"时才需要它。Eric的演示使用了一个计时器对象,因此当计时器到期时,他必须手动“解决”自己创建的“deferred”对象。正如Matt所说,如果是AJAX查询,则不需要它。 - Alnitak
从方法中删除成功并使用$.when(m1(),m2()).then(m3),其中m3 = function(data1, data2)。 - Guillaume86
@Guillaume86:我尝试了你的建议,使用m3 = function(data1, data2)删除成功,但是data1和data2的值都变成了未定义。你能否修改我的代码[http://jsfiddle.net/f4hmL/3/],展示如何让它工作吗? - Ashish
3个回答

76
function showData(data1, data2) {
    alert(data1[0].max_id);
    alert(data2[0].max_id);
}

function method1() {
    return $.ajax("http://search.twitter.com/search.json", {
        data: {
            q: 'ashishnjain'
        },
        dataType: 'jsonp'
    });
}

function method2() {
    return $.ajax("http://search.twitter.com/search.json", {
        data: {
            q: 'ashishnjain'
        },
        dataType: 'jsonp'
    });
}

$.when(method1(), method2()).then(showData);​

这是一个有效的jsFiddle示例


看起来有点奇怪,data1 应该是一个包含 m1() 成功回调参数的数组,而 data2 是一个包含 m2() 回调参数的数组。 - Guillaume86
当将多个Deferred对象传递给jQuery.when时,该方法会返回一个来自新的“主”Deferred对象的Promise,该对象跟踪它所传递的所有Deferred对象的聚合状态。——来自手册的引用。 - HarryFink
没有解释主deferred如何根据参数解决,这是两年前提出的问题 ;) - Guillaume86
弹跳不起作用。阻止了一个源为“http://fiddle.jshell.net”的框架访问一个源为“http://jsfiddle.net”的框架。协议、域和端口必须匹配。 - oligofren
Chrome的更新破坏了很多使用raw.github网址的代码片段。你可以寻找替代的脚本网址,这样就没问题了。 - Guillaume86
显示剩余4条评论

36
问题在于你把 showData() 传递给了 then(),而不是传递 showData 函数的引用。你应该向 .then() 传递一个函数引用:
$.when(method1(), method2())
    .then(showData);
或者
$.when(method1(), method2())
    .then(function () {
        showData();
    });

编辑

我已经制作了一个可运行的演示版。问题的一部分(至少在您发布的代码片段中)是没有名为$callback的回调函数。另一个问题是回调名称'$callback'中的$

因此,删除jsonp: '$callback' ajax选项,以便jQuery默认使用名为callback的回调函数,并定义一个名为callback的函数,这样就可以正常工作了。


尝试了两种方法,但结果仍然相同。showData中的数据参数仍然是“未定义”。 - Ashish
看到我的修改。你的代码里至少还有两个问题。 - Matt Ball
是的,看起来对了 - 如果你调用 .then(showData()) 它会立即执行 showData 然后将其结果传递给 .then。正如Matt所说 - 传递函数引用。 - Alnitak
非常感谢Matt。在您的示例帮助下,我在这里提供了一个可工作的示例[http://jsfiddle.net/f4hmL/3/]。 - Ashish

-4

我稍微修改了你的代码,使它更容易理解了... 我还没有测试过,请试一下

var count = 0;
function countResponse(data) {
    count++;
    if(count==2)
    {
        // Do something after getting responce from both ajax request
    }
};

var method1 = function() {
    return $.ajax('localhost/MyDataService/DataMethod_ReturnsData', {
        dataType: "jsonp",
        jsonp: "$callback",
        success: function(data) {
            countResponse(data)
        }
    });
};

var method2 = function() {
    return $.ajax('localhost/MyDataService/DataMethod_ReturnsCount', {
        dataType: "jsonp",
        jsonp: "$callback",
        success: function(data) {
            countResponse(data)
        }
    });
};

1
这并没有回答我的问题,因为countReponse将会失去其中一个数据,无论是计数还是实际数据,因为method1和method2中的ajax调用是异步的。无论哪个调用后执行,都会有数据,但第一个数据将会丢失。 - Ashish
2
jQuery延迟对象的作用在于,您无需计算响应数量即可继续进行。 - Alnitak
2
同意前两个评论。这根本没有回答问题 - 尤其是因为它没有使用jQuery deferreds。 - Matt Ball
抱歉,Ashish,我误解了,因为你没有提到需要存储两个响应。 - Haresh Vidja

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接