Цепочка запросов ajax с отложенным jQuery - PullRequest
12 голосов
/ 08 ноября 2011

У меня есть веб-приложение, которое должно вызывать сервер несколько раз. До сих пор у меня была длинная цепочка обратных вызовов; но я бы хотел использовать функциональность when, then и т. д. в jQuery. Однако после использования 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 ]

29 голосов
/ 16 марта 2013

В качестве обновления:

В современном jquery (1.8+) вам не нужны предварительные , когда , потому что get возвращает отложенное обещание.

Кроме того, труба устарела.Вместо этого используйте , затем .Только обязательно верните результат нового get, который становится Обещанием, присоединенным к последующим , затем / * done * / fail звонков.

Итак:

$.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); 
});
12 голосов
/ 08 ноября 2011

Все три обратных вызова (два с then и один с done) применяются к одному и тому же запросу - исходному вызову when. Это связано с тем, что then возвращает один и тот же отложенный объект, а не новый, так что вы можете добавить несколько обработчиков событий.

Вам нужно использовать 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);
});
1 голос
/ 13 января 2014

Ответ, который дал cdr, который имеет самый высокий голос в данный момент, неверен.

Когда у вас есть функции a, b, c, каждый возвращает объект $ .Deferred () и цепочку функцийкак показано ниже:

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

И b, и c будут выполняться после разрешения обещания, возвращенного из a.Так как обе функции then () связаны с обещанием a, это работает подобно другим цепочкам Jquery, таким как:

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

, где функции html () и css () вызываются для объекта, возвращаемого из$ ('# id');

Таким образом, чтобы выполнить a, b, c после разрешения обещания, возвращенного предыдущей функцией, вам необходимо сделать следующее:

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

Здесьвызов функции c привязан к обещанию, возвращенному функцией b.

Вы можете проверить это, используя следующий код:

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 () с resol () отклонить (), и вы увидите разницу.

1 голос
/ 30 октября 2013

Вот удивительно простой и очень эффективный плагин цепочки / очереди AJAX. Он выполнит вам ajax методы в последовательности один за другим.

Он работает, принимая массив методов и затем выполняя их последовательно. Он не выполнит следующий метод, ожидая ответа.

// --- ЭТА ЧАСТЬ - ВАШ КОД -----------------------

$ (документ) .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 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'); }

} 
* *} Тысяча двадцать-один
0 голосов
/ 23 декабря 2013

Я подумал, что оставлю это небольшое упражнение здесь для тех, кто может найти его полезным, мы создаем массив запросов, и когда они завершаются, мы можем запустить функцию обратного вызова:

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)
});
0 голосов
/ 05 ноября 2013
<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>
0 голосов
/ 25 августа 2013

Мой способ - применить функцию обратного вызова:

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

где A, B можно записать как

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