javascript 使用 jQuery 的延迟链接 ajax 请求

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8049041/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 02:06:36  来源:igfitidea点击:

Chaining ajax requests with jQuery's deferred

javascriptjqueryjquery-deferred

提问by Anteru

I have a web app which must call the server multiple times. So far, I had a long nested callback chain; but I would like to use jQuery's when,thenetc. functionality. However, I can't seem to get stuff running again after using a then.

我有一个必须多次调用服务器的网络应用程序。到目前为止,我有一个很长的嵌套回调链;但我想用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);
});

What am I doing wrong? I guess its some scoping issue, as I can see the second getcall being executed. Using two different argsvariables does not help as the argument passed to the done function is still the first getrequest.

我究竟做错了什么?我想这是一些范围问题,因为我可以看到get正在执行的第二个调用。使用两个不同的args变量无济于事,因为传递给 done 函数的参数仍然是第一个get请求。

回答by cdr

As an update:

作为更新:

With modern jquery (1.8+) you don't need the preliminary whenbecause getreturns a Deferred Promise.

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

Also, pipeis deprecated. Use theninstead. Just be sure to return the result of the new get which becomes the Promise attached to by subsequent then/*done*/failcalls.

此外,管道已被弃用。改用then。只需确保返回新 get 的结果,该结果将成为后续then/*done*/失败调用所附加的 Promise 。

So:

所以:

$.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); 
});

回答by lonesomeday

All three callbacks (the two with thenand the one with done) are applied to the same request – the original whencall. This is because thenreturns the same Deferred object, rather than a new one, so that you can add multiple event handlers.

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

You need to use pipeinstead.

你需要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);
});

回答by MarzSocks

Here is an wonderfully simple and highly effective AJAX chaining / queue plugin. It will execute you ajax methods in sequence one after each other.

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

It works by accepting an array of methods and then executing them in sequence. It wont execute the next method whilst waiting for a response.

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

//--- THIS PART IS YOUR CODE -----------------------

$(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 });

});

//--- THIS PART IS THE AJAX PLUGIN -------------------

$.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'); }

} 

}

//--- 这部分是你的代码 ---------------

$(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 = 函数(选项){

//? 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'); }

} 

}

回答by cl yu

The answer cdr gave, which has the highest vote at the moment, is not right.

目前票数最高的cdr给出的答案是不正确的。

When you have functions a, b, c each returns a $.Deferred() object, and chains the functions like the following:

当你有函数 a、b、c 时,每个函数都返回一个 $.Deferred() 对象,并像下面这样链接函数:

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

Both b and c will run once the promise returned from a is resolved. Since both then() functions are tied to the promise of a, this works similiar to other Jquery chaining such as:

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

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

where both html() and css() function are called on the object returned from $('#id');

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

So to make a, b, c run after the promise returned from the previous function is resolved, you need to do this:

所以要让a,b,c在前一个函数返回的promise被解析后运行,你需要这样做:

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

Here the call of function c is tied to the promise returned from function b.

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

You can test this using the following code:

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

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)
});

Change the promise in function b() from resolve() to reject() and you will see the difference.

将函数 b() 中的 promise 从 resolve() 更改为 reject() ,您将看到不同之处。

回答by Du?an Stanojevi?

<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>

回答by iamwhitebox

I thought I would leave this little exercise here for anyone who may find it useful, we build an array of requests and when they are completed, we can fire a callback function:

我想我会把这个小练习留在这里给任何可能觉得有用的人,我们构建一个请求数组,当它们完成时,我们可以触发一个回调函数:

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)
});

回答by kungtu

My way is to apply callback function:

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

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

where A, B can be written as

其中 A, B 可以写成

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