jQuery Deferred不起作用

6

我正在尝试一段代码:

function search(query) {
    var dfr = $.Deferred();
    $.ajax({
        url: "http://search.twitter.com/search.json",
        data: {
            q: query
        },
        dataType: 'jsonp',
        success: dfr.resolve
    });
    return dfr.promise();
}

Test = {
    start: function(){
        alert("Starting");
    }
};

function gotresults(data) {
    alert(data.max_id);
}

function showDiv() {
    $('<div />').html("Results received").appendTo('body');
}

$.when(search('ashishnjain'))
    .then(gotresults)
    .then(showDiv);

这个代码按预期工作。但是,当我这样写时:

Test.start()
    .then(search('ashishnjain'))
    .then(gotresults)
    .then(showDiv);

它只会弹出“Starting”并终止。可以在http://jsfiddle.net/XQFyq/2/找到一个工作示例。我做错了什么吗?


start() 函数没有返回任何东西,所以我猜你不能在这里使用链式调用。 - pimvdb
即使将搜索测试并从搜索开始也无济于事。 - Ashish
“Test” 没有相应的方法。你看过 Firebug/Web Inspector 吗? - kirilloid
1个回答

8

Test不是一个延迟对象,因此它没有.then()方法。 .when() 一个延迟对象,所以当您调用.when()时,它会起作用。

您的$.ajax()调用一个延迟对象,因此,如果您将其作为'Test.start()方法的一部分返回,则可以添加.then()回调函数请参见此处示例.then()回调函数将在ajax调用已解析,即已返回其数据后调用,但我认为这并不是使用deferred对象的正确方式。以下是我认为更符合其预期使用方式的示例:

function searchTwitter(query){
    $.ajax({
            url: "http://search.twitter.com/search.json",
            data: {
                q: query
            },
            dataType: 'jsonp',
            success: function(data){return data;}
        })
        .then(gotresults)
        .then(showDiv)
        .fail(showFailDiv);
};

function gotresults(data) {
    alert(data.max_id);
}

function showDiv() {
    $('<div />').html("Results received").appendTo('body');
}

function showFailDiv() {
    $('<div />').html("Results <b>NOT</b> received").appendTo('body');
}

// Starting can be done with a click:

$("#searchTwitter").click(function(){
   searchTwitter($("#searchName").val()); 
});

// OR a static call:
searchTwitter("ashishnjain");

点击 这里 查看它的工作原理。

如果您希望在例如showDiv()中返回数据,请将其更改为showDiv(data).....


这是另一个示例,演示如何创建自己的延迟对象,而不是依赖于.ajax()调用的延迟对象。 这与您的原始示例更接近-例如,如果您想要查看失败情况,请将url更改为http://DONTsearch.twitter.com/search.json 此处有示例

var dfr;

function search(query) {
    $.ajax({
        url: "http://search.twitter.com/search.json",
        data: {
            q: query
        },
        dataType: 'jsonp',
        success: function(data){dfr.resolve(data);},
        error:  function(){dfr.reject();}
    });
}

Test = {
    start: function(){
        dfr = $.Deferred();
        alert("Starting");
        return dfr.promise();        
    }
};


function gotresults(data) {
    alert(data.max_id);
}

function showDiv() {
    $('<div />').html("Results received").appendTo('body');
}

function showFailDiv() {
    $('<div />').html("Results <b>NOT</b> received").appendTo('body');
}

Test.start()
    .then(search('ashishnjain'))
    .then(gotresults)
    .then(showDiv)
    .fail(showFailDiv);

针对评论的更新:

在您的 第11版 中,您没有告知失败的延迟对象,因此它将永远不会调用.fail()回调函数。为了纠正这个问题,如果.fail() (error:.......)出现错误,请使用ajax解释来通知延迟对象发生错误error: drf.reject - 这将运行.fail()回调。

至于你看到的ShowMoreCode()直接运行的原因是,.then()调用是回调函数,如果你传递一个函数的字符串表示形式,比如:.then(ShowDiv),一旦轮到它的回调函数,它将寻找该名称的函数。如果你传递一个函数的调用.then(someMoreCode('Ashish')),它将运行该函数。试试把.then(showDiv)改成.then(showDiv()),你会注意到代码运行后,它将显示来自showDiv()的代码。

如果你把.then(ShowMoreCode('Ashish'))改成.then(ShowMoreCode),你可以访问$.ajax()调用返回的数据。像这样:

function someMoreCode(name) {
    alert('Hello ' + name.query);
}

请看这里:运行中的.fail()未能正常工作的


感谢您提供详细的回复。然而,在尝试上述代码后,我发现failed仍然没有被调用。我甚至将url更改为http://DONTsearch.twitter.com/search.json,但没有运气。我还注意到在此代码http://jsfiddle.net/ashishnjain/XQFyq/11/中,函数someMoreCode甚至在搜索代码之前被调用。我们不能将someMoreCode链接起来,在所有代码完成后执行吗? - Ashish
请参阅答案的更新,希望能够帮助您的代码。 - Scoobler
再次感谢您提供如此详细的解释。但是,您更新的回复意味着我们无法将自定义函数与与ajax调用无关的自定义值连接到链中。someMoreCode('Ashish')只是一个示例。实际上,在我的代码中,我必须在ajax调用响应后显示另一个div。例如,如果我收到响应中的记录,则显示该div,否则我将显示“没有记录存在”的自定义语句。但最终,someMoreCode应该在最后执行。我们是否可以以某种方式挂接自定义参数到ajax调用中,这些参数可以像您所说的name.query一样从someMoreCode访问? - Ashish
1
当您调用dfr.resolve时,不需要括号,它是一个回调函数 - 因此ajax调用返回的数据将在回调函数中可用 - 所以在示例中,您可以通过调用gotResults(data)来访问数据 - 数据现在在gotResults中作为var data可用。如果您调用someMoreCode(name) - 数据现在对函数作为var name可用 - 它是相同的数据。由于这是ajax响应,因此您可以执行someMoreCode(data,status) - status应该是一个字符串,表示成功。 - Scoobler
1
现在,如果您想将特定的函数调用添加到回调中。您可以将其作为包装对函数的调用的函数传递....因此,不是.then(someMoreCode('Ashish')) _我们知道这行不通_,您可以像这样包装它:.then(function(){someMoreCode('Ashish')})。在这里查看它的工作原理。我已经包含了一些额外的函数,希望能够展示如何在延迟对象和回调之间以不同的方式移动数据。 - Scoobler

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