12

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

4

7 回答 7

29

作为更新:

使用现代 jquery (1.8+) 你不需要初步when因为get返回一个 Deferred Promise。

此外,不推荐使用管道。使用then代替。只需确保返回新 get 的结果,该结果成为后续then /*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); 
});
于 2013-03-16T16:15:47.027 回答
12

所有三个回调(两个 withthen和一个 with 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);
});
于 2011-11-08T10:37:01.093 回答
1

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

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

} 

}

于 2013-10-30T11:31:07.680 回答
1

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

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

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:

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

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

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

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

Here the call of function c is tied to the promise returned from function 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.

于 2014-01-13T19:39:15.647 回答
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>
于 2013-11-05T13:42:14.610 回答
0

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)
});
于 2013-12-23T16:48:38.427 回答
-2

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

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

其中 A, B 可以写成

function A(callback)
$.ajax{
    ...
    success: function(result){
        ...
        if (callback) callback();
   }
}
于 2013-08-25T04:21:56.003 回答