Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 05.08.2020, 05:41
Аватар для MC-XOBAHCK
Профессор
Отправить личное сообщение для MC-XOBAHCK Посмотреть профиль Найти все сообщения от MC-XOBAHCK
 
Регистрация: 06.08.2017
Сообщений: 473

Ajax запросы внутри цикла
Здравствуйте! Подскажите пожалуйста, как мне решить такую задачу.

У меня внутри цикла Ajax-запрос на сервер. Как мне правильно сделать чтобы следующая итерация цикла начиналась после того как придёт ответ с сервера для текущей итерации?

Вот код:
loader.classList.remove('hide');

arr.forEach(el => {
    let tableName = el.dataset.table;

    $.request('onAjax', {
        data: {
            'table': tableName
        },
        success: function(data) {
            // ответ сервера об успешном выполнении запроса
        },
        error: function(data) {
            // ответ об ошибке
        },
        complete: function(data) {
            // выполнится независимо от успешного запроса или ошибки
        }
    });

});

loader.classList.add('hide');


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

В общем без помощи никак...

Последний раз редактировалось MC-XOBAHCK, 05.08.2020 в 05:46.
Ответить с цитированием
  #2 (permalink)  
Старый 05.08.2020, 08:54
Аватар для voraa
Профессор
Отправить личное сообщение для voraa Посмотреть профиль Найти все сообщения от voraa
 
Регистрация: 03.02.2020
Сообщений: 2,700

Если цикл должен продолжаться независимо от ошибок, по-простому, сильно не переделывая можно так с использованием Promise

const ajaxloop = (arr) => { 
	let prom = Promise.resolve(true)
	for (const el of arr) {
		const tableName = el.dataset.table;
		prom = prom.then ( _ =>  return new Promise (res => {
				$.request('onAjax', {
					data: {
						'table': tableName
					},
					success: function(data) {
							// ответ сервера об успешном выполнении запроса
					},
					error: function(data) {
							// ответ об ошибке
					},
					complete: function(data) {
							// выполнится независимо от успешного запроса или ошибки
						res()  // Тут промис разрешился
					}
				});
			})
		)
	}
       return prom
}


Вызываем все это так

loader.classList.remove('hide');
ajaxloop (arr)
  .then (_ => loader.classList.add('hide');) // что то там гасим, когда все вызовы закончатся.
Ответить с цитированием
  #3 (permalink)  
Старый 05.08.2020, 09:59
Аватар для MC-XOBAHCK
Профессор
Отправить личное сообщение для MC-XOBAHCK Посмотреть профиль Найти все сообщения от MC-XOBAHCK
 
Регистрация: 06.08.2017
Сообщений: 473

voraa,
Спасибо! Буду пробовать.

А можете подсказать, мне нужно индекс итерации прокинуть в ответ сервера (success и error).
Нашёл метод entries но боюсь что вставлю так что всё сломаю.
Ответить с цитированием
  #4 (permalink)  
Старый 05.08.2020, 10:08
Аватар для voraa
Профессор
Отправить личное сообщение для voraa Посмотреть профиль Найти все сообщения от voraa
 
Регистрация: 03.02.2020
Сообщений: 2,700

Тогда так.

const ajaxloop = (arr) => {
    let prom = Promise.resolve(true)
    for (let i = 0; i < arr.length; i++) {
        let el = arr[i]
        const tableName = el.dataset.table;
        prom = prom.then ( _ =>  return new Promise (res => {
                $.request('onAjax', {
                    data: {
                        'table': tableName
                    },
                    success: function(data) {
                            // Тут можно использовать i
                            // ответ сервера об успешном выполнении запроса
                    },
                    error: function(data) {
                            // ответ об ошибке
                    },
                    complete: function(data) {
                            // выполнится независимо от успешного запроса или ошибки
                        res()  // Тут промис разрешился
                    }
                });
            })
        )
    }
       return prom
}
Ответить с цитированием
  #5 (permalink)  
Старый 05.08.2020, 10:19
Аватар для voraa
Профессор
Отправить личное сообщение для voraa Посмотреть профиль Найти все сообщения от voraa
 
Регистрация: 03.02.2020
Сообщений: 2,700

Я пользовался такой функцией
/*
	Асинхронно обрабатывает элементы arr. Каждый элемент обрабатывается после обработки предыдущего
	функция callback принимает параметры
		el - элемент массива
		i - индекс элемента 
		arr - сам массив
	 и должна возвращать Promise, разрешаемый после обработки элемента.
	 Если Promise отклоняется, обработка цикла прерывается
	 
	 Возвращает Promise, разрешенный после обработки всех элементов или отклоненный, если какой либо элемент
	 вернул отклоненный Promise
*/
asyncForEach (arr, callback) {
 
 let prom = Promise.resolve(true) 
 for (let i = 0; i< arr.length; i++) {
	let el = arr[i];
	prom = prom.then ( _ => callback (el, i, arr))
 } 
 return prom.then ( _ => arr.length);
}


Тогда можно так

const ajaxcall = (el, i) => {
	const tableName = el.dataset.table;
	return new Promise ((res, rej) => {
		$.request('onAjax', {
				data: {
					'table': tableName
				},
				success: function(data) {
									// ответ сервера об успешном выполнении запроса
				},
				error: function(data) {
									// ответ об ошибке
					// rej(data) // Если вызывать, цикл прервется	
				},
				complete: function(data) {
									// выполнится независимо от успешного запроса или ошибки
					res()  // Тут промис разрешился
				}
			});
		})
}

loader.classList.remove('hide');
asyncForEach (arr, ajaxcall )
  .then (_ => loader.classList.add('hide');) // что то там гасим, когда все вызовы закончатся.
// .catch (data =>{
    // Тут можно обработать, если где то произошла ошибка и цикл прошел не полностью
//})

Последний раз редактировалось voraa, 05.08.2020 в 10:24.
Ответить с цитированием
  #6 (permalink)  
Старый 05.08.2020, 11:46
Аватар для MC-XOBAHCK
Профессор
Отправить личное сообщение для MC-XOBAHCK Посмотреть профиль Найти все сообщения от MC-XOBAHCK
 
Регистрация: 06.08.2017
Сообщений: 473

Сообщение от voraa
Тогда так.
Этот вариант работает, только в 6 строке нужно ретурн убрать

Вместо
prom = prom.then ( _ =>  return new Promise (res => {


вот так
prom = prom.then ( _ =>  new Promise (res => {


Мне вариант с промисами понятен. Я просто взять функцию в переменную не додумываюсь.
Вон ниже в блоке Похожие темы мой же похожий вопрос про setTimeout. Тоже решение - в переменную взять. Я вчера ещё сидел смотрел на тот вариант, но решения придумать не смог.

Спасибо за помощь!
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Передача значения внутри тега <label> на сервер при помощи AJAX MaksimZykov AJAX и COMET 4 22.10.2018 09:51
Можно ли применять setTimeout внутри цикла? MC-XOBAHCK Общие вопросы Javascript 12 27.04.2018 17:34
Вложенные Ajax запросы Sherminator AJAX и COMET 10 03.10.2016 05:11
ajaxupload внутри ajax запроса Eliot456 AJAX и COMET 6 15.09.2016 23:45
старые(выполненые) ajax запросы archcoffe jQuery 7 03.05.2012 11:50