用jQuery延迟链接ajax请求

时间:2011-11-08 10:32:17

标签: javascript jquery jquery-deferred

我有一个必须多次调用服务器的Web应用程序。到目前为止,我有一个很长的嵌套回调链;但我想使用jQuery的whenthen等功能。但是,在使用then后,我似乎无法再次运行。

$
.when ($.get('pages/run-tool.html'))
.then (function (args)
{
    // This works fine
    alert(args);
    $('#content').replaceWith (args);
    $('#progress-bar').progressbar ({value: 0});
})
.then ($.get('pages/test.html'))
.done (function(args)
{
    // This prints the same as the last call
    alert (args);
});

我做错了什么?我猜它有一些范围问题,因为我可以看到正在执行的第二个get调用。使用两个不同的args变量没有帮助,因为传递给done函数的参数仍然是第一个get请求。

7 个答案:

答案 0 :(得分:29)

作为更新:

使用现代jquery(1.8+),时不需要初步,因为 get 会返回延迟承诺。

此外,不推荐使用 pipe 。请改用然后。只需确保返回新get的结果,该结果将成为后续然后 / * done * / fail 调用附加的Promise。

所以:

$.get('pages/run-tool.html')
.then (function (args) { // this will run if the above .get succeeds
    // This works fine
    alert(args);
    $('#content').replaceWith (args);
    $('#progress-bar').progressbar ({value: 0});
})
.then (function() { // this will run after the above then-handler (assuming it ran)
    return $.get('pages/test.html'); // the return value creates a new Deferred object
})
.done (function(args) { // this will run after the second .get succeeds (assuming it ran)
    alert (args); 
});

答案 1 :(得分:12)

所有三个回调(两个then和一个done)都应用于同一个请求 - 原始when来电。这是因为then返回相同的Deferred对象而不是新对象,因此您可以添加多个事件处理程序。

您需要改为使用pipe

$
.when ($.get('pages/run-tool.html'))
.then (function (args)
{
    // This works fine
    alert(args);
    $('#content').replaceWith (args);
    $('#progress-bar').progressbar ({value: 0});
})
.pipe (function() { 
    return $.get('pages/test.html'); // the return value creates a new Deferred object
})
.done (function(args)
{
    alert (args);
});

答案 2 :(得分:1)

这是一个非常简单且高效的AJAX链接/队列插件。它会一个接一个地按顺序执行ajax方法。

它的工作原理是接受一组方法,然后按顺序执行它们。它在等待响应时不会执行下一个方法。

  

// ---此部分是您的代码-----------------------

     

$(document).ready(function(){

var AjaxQ = [];
AjaxQ[0] = function () { AjaxMethod1(); }
AjaxQ[1] = function () { AjaxMethod2(); }
AjaxQ[3] = function () { AjaxMethod3(); }

//Execute methods in sequence
$(document).sc_ExecuteAjaxQ({ fx: AjaxQ });
     

});

     

// ---这部分是AJAX插件-------------------

     

$。fn.sc_ExecuteAjaxQ = function(options){

//? Executes a series of AJAX methods in dequence

var options = $.extend({

    fx: [] //function1 () { }, function2 () { }, function3 () { }

}, options);

if (options.fx.length > 0) {

    var i = 0;

    $(this).unbind('ajaxComplete');
    $(this).ajaxComplete(function () {

        i++;
        if (i < options.fx.length && (typeof options.fx[i] == "function")) { options.fx[i](); }
        else { $(this).unbind('ajaxComplete'); }

    });

    //Execute first item in queue
    if (typeof options.fx[i] == "function") { options.fx[i](); }
    else { $(this).unbind('ajaxComplete'); }

} 
     

}

答案 3 :(得分:1)

目前投票率最高的答案给出的答案是不对的。

当你有函数a,b,c时,每个函数返回一个$ .Deferred()对象,并将函数链接如下:

a().then(b).then(c)

一旦从a返回的承诺得到解决,b和c都将运行。由于then()函数都与a的承诺相关联,因此与其他Jquery链接类似,例如:

$('#id').html("<div>hello</div>").css({display:"block"})

在从$(&#39;#id&#39;)返回的对象上调用html()和css()函数;

因此,要解决从上一个函数返回的promise后运行a,b,c,你需要这样做:

a().then(function(){
    b().then(c)
});

这里函数c的调用与函数b返回的promise相关联。

您可以使用以下代码对此进行测试:

function a() {
    var promise = $.Deferred();
    setTimeout(function() {
        promise.resolve();
        console.log("a");
    }, 1000);
    return promise;
}

function b() {
    console.log("running b");
    var promise = $.Deferred();
    setTimeout(function () {
        promise.resolve();
        console.log("b");
    }, 500);
    return promise;
}

function c() {
    console.log("running c");
    var promise = $.Deferred();
    setTimeout(function () {
        promise.resolve();
        console.log("c");
    }, 1500);
    return promise;
}

a().then(b).then(c);
a().then(function(){
    b().then(c)
});

将函数b()中的promise从resolve()更改为reject(),您将看到差异。

答案 4 :(得分:0)

<script type="text/javascript">

    var promise1 = function () {
        return new
        $.Deferred(function (def) {
            setTimeout(function () {
                console.log("1");
                def.resolve();
            }, 3000);
        }).promise();
    };

    var promise2 = function () {
        return new
        $.Deferred(function (def) {
            setTimeout(function () {
                console.log("2");
                def.resolve();
            }, 2000);
        }).promise();
    };

    var promise3 = function () {
        return new
        $.Deferred(function (def) {
            setTimeout(function () {
                console.log("3");
                def.resolve();
            }, 1000);
        }).promise();
    };

    var firstCall = function () {
        console.log("firstCall");
        $.when(promise1())
        .then(function () { secondCall(); });
    };

    var secondCall = function () {
        console.log("secondCall")
        $.when(promise2()).then(function () { thirdCall(); });
    };

    var thirdCall = function () {
        console.log("thirdCall")
        $.when(promise3()).then(function () { console.log("done"); });
    };


    $(document).ready(function () {
        firstCall();
    });
</script>

答案 5 :(得分:0)

我想我会把这个小小的练习留给那些可能觉得有用的人,我们建立一系列请求,当它们完成后,我们可以发出一个回调函数:

var urls = [{
    url: 'url1',
    data: 'foo'
}, {
    url: 'url2',
    data: 'foo'
}, {
    url: 'url3',
    data: 'foo'
}, {
    url: 'url4',
    data: 'foo'
}];
var requests = [];
var callback = function (result) {
    console.log('done!');
};

var ajaxFunction = function () {
    for (var request, i = -1; request = urls[++i];) {
        requests.push($.ajax({
            url: request.url,
            success: function (response) {
                console.log('success', response);
            }
        }));
    }
};

// using $.when.apply() we can execute a function when all the requests 
// in the array have completed
$.when.apply(new ajaxFunction(), requests).done(function (result) {
    callback(result)
});

答案 6 :(得分:-2)

我的方法是应用回调函数:

A(function(){
       B(function(){
            C()})});

其中A,B可写为

function A(callback)
$.ajax{
    ...
    success: function(result){
        ...
        if (callback) callback();
   }
}