Упорядочивание ajax запросы

Я нахожу, что иногда должен выполнять итерации некоторого набора и заставлять ajax призвать к каждому элементу. Я хочу, чтобы каждый вызов возвратился прежде, чем переместиться в следующий элемент так, чтобы я не уничтожал сервер с запросами - который часто приводит к другим проблемам. И я не хочу устанавливать асинхронный на ложь и замораживать браузер.

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

У кого-либо есть умный шаблон разработки для того, как аккуратно работать через набор, делающий ajax призывы к каждому объекту?

62
задан 17 June 2010 в 00:14

5 ответов

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

Это теперь возможно также использование собственной поддержки обещания, представленной в ES6. Можно перенести вызов ajax в обещание и возвратить его обработчику элемента.

function ajaxPromise(elInfo) {
    return new Promise(function (resolve, reject) {
        //Do anything as desired with the elInfo passed as parameter

        $.ajax({
            type: "POST",
            url: '/someurl/',
            data: {data: "somedata" + elInfo},
            success: function (data) {
                //Do anything as desired with the data received from the server,
                //and then resolve the promise
                resolve();
            },
            error: function (err) {
                reject(err);
            },
            async: true
        });

    });
}

Теперь вызывают функцию рекурсивно, от того, где у Вас есть набор элементов.

function callAjaxSynchronous(elCollection) {
    if (elCollection.length > 0) {
        var el = elCollection.shift();
        ajaxPromise(el)
        .then(function () {
            callAjaxSynchronous(elCollection);
        })
        .catch(function (err) {
            //Abort further ajax calls/continue with the rest
            //callAjaxSynchronous(elCollection);
        });
    }
    else {
        return false;
    }
}
2
ответ дан 31 October 2019 в 13:41

Можно достигнуть того же самого с помощью then.

var files = [
  'example.txt',
  'example2.txt',
  'example.txt',
  'example2.txt',
  'example.txt',
  'example2.txt',
  'example2.txt',
  'example.txt'
];

nextFile().done(function(){
  console.log("done",arguments)
});

function nextFile(text){
  var file = files.shift();
  if(text)
    $('body').append(text + '<br/>');
  if(file)
    return $.get(file).then(nextFile);
}

http://plnkr.co/edit/meHQHU48zLTZZHMCtIHm?p=preview

1
ответ дан 31 October 2019 в 13:41

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

, Но я уверен, что это должно также работать при итерации через набор. В этом случае это может поставить запросы в очередь и может отправить единственный вызов Ajax вместо 12.

queueing = {
    callTimeout:                 undefined,
    callTimeoutDelayTime:        1000,
    callTimeoutMaxQueueSize:     12,
    callTimeoutCurrentQueueSize: 0,

    queueCall: function (theCall) {
        clearTimeout(this.callTimeout);

        if (this.callTimeoutCurrentQueueSize >= this.callTimeoutMaxQueueSize) {
            theCall();
            this.callTimeoutCurrentQueueSize = 0;
        } else {
            var _self = this;

            this.callTimeout = setTimeout(function () {
                theCall();
                _self.callTimeoutCurrentQueueSize = 0;
            }, this.callTimeoutDelayTime);
        }

        this.callTimeoutCurrentQueueSize++;
    }
}
1
ответ дан 31 October 2019 в 13:41

Быстрое и небольшое решение с помощью задержанных обещаний. Хотя это использует jQuery $.Deferred, любой другой должен сделать.

var Queue = function () {
    var previous = new $.Deferred().resolve();

    return function (fn, fail) {
        return previous = previous.then(fn, fail || fn);
    };
};

Использование, звоните для создания новых очередей:

var queue = Queue();

// Queue empty, will start immediately
queue(function () {
    return $.get('/first');
});

// Will begin when the first has finished
queue(function() {
    return $.get('/second');
});

См. пример с бок о бок сравнение асинхронных запросов.

13
ответ дан 31 October 2019 в 13:41

Да, в то время как другие ответы будут работать, они - много кода и грязного взгляда. Frame.js был разработан для изящного обращения к этой ситуации. https://github.com/bishopZ/Frame.js

, Например, это заставит большинство браузеров зависать:

for(var i=0; i<1000; i++){
    $.ajax('myserver.api', { data:i, type:'post' });
}

, В то время как это не будет:

for(var i=0; i<1000; i++){
    Frame(function(callback){
        $.ajax('myserver.api', { data:i, type:'post', complete:callback });
    });
}
Frame.start();

кроме того, с помощью Кадра позволяет Вам водопаду объекты ответа и соглашение с ними всеми после того, как все серии запроса Ajax завершились (если Вы хотите к):

var listOfAjaxObjects = [ {}, {}, ... ]; // an array of objects for $.ajax
$.each(listOfAjaxObjects, function(i, item){
    Frame(function(nextFrame){ 
        item.complete = function(response){
            // do stuff with this response or wait until end
            nextFrame(response); // ajax response objects will waterfall to the next Frame()
        $.ajax(item);
    });
});
Frame(function(callback){ // runs after all the AJAX requests have returned
    var ajaxResponses = [];
    $.each(arguments, function(i, arg){
        if(i!==0){ // the first argument is always the callback function
            ajaxResponses.push(arg);
        }
    });
    // do stuff with the responses from your AJAX requests
    // if an AJAX request returned an error, the error object will be present in place of the response object
    callback();
});
Frame.start()
2
ответ дан 31 October 2019 в 13:41

Другие вопросы по тегам:

Похожие вопросы: