Я нахожу, что иногда должен выполнять итерации некоторого набора и заставлять ajax призвать к каждому элементу. Я хочу, чтобы каждый вызов возвратился прежде, чем переместиться в следующий элемент так, чтобы я не уничтожал сервер с запросами - который часто приводит к другим проблемам. И я не хочу устанавливать асинхронный на ложь и замораживать браузер.
Обычно это включает установку некоторого контекста итератора, что я ступаю через в каждый обратный вызов успеха. Я думаю, что должен быть более чистый более простой путь?
У кого-либо есть умный шаблон разработки для того, как аккуратно работать через набор, делающий ajax призывы к каждому объекту?
Я отправляю этот ответ, думая, что он мог бы помочь другим людям в будущем, ища некоторые простые решения в том же сценарии.
Это теперь возможно также использование собственной поддержки обещания, представленной в 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;
}
}
Можно достигнуть того же самого с помощью 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);
}
Я предложил бы немного более сложный подход, который является допускающим повторное использование для различных случаев.
я использую его, например, когда я должен замедлить последовательность вызова, когда пользователь вводит в текстовом редакторе.
, Но я уверен, что это должно также работать при итерации через набор. В этом случае это может поставить запросы в очередь и может отправить единственный вызов 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++;
}
}
Быстрое и небольшое решение с помощью задержанных обещаний. Хотя это использует 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');
});
См. пример с бок о бок сравнение асинхронных запросов.
Да, в то время как другие ответы будут работать, они - много кода и грязного взгляда. 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()