Задать вопрос
@kr_ilya

Как асинхронно перебрать массив, с задержкой между итерациями?

Нужна async/await foreach функция с задержкой выполнения.
На данный момент есть такое решение, но оно работает не совсем правильно:

fn.asyncDelayedForEach = async (array, callback, timeout) => {
	var i = 0,
    l = array.length,
    caller = async () => {
      await callback.call(array, array[i], i, array);
      (++i < l) && setTimeout(caller, timeout);
    };
    caller();
}

(async () => {
	await fn.asyncDelayedForEach([1,3,4], (item, i, arr) => {
		console.log(item);
	}, 1000)

console.log('a')
console.log('b')
}
)()

Данный код возвращает

1
a
b
3
4

Причем задержка отрабатывает как надо, т.е. 1, 3, 4 возвращаются постепенно с интервалом 1 секунду, а вот

console.log('a')
console.log('b')

должны срабатывать только после завершения выполнения функции asyncDelayedForEach.
Т.е последовательность вывода должна быть такая:

1
3
4
a
b

Как исправить?
  • Вопрос задан
  • 172 просмотра
Подписаться 1 Средний Комментировать
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
Как реализуется задержка - создаём промис, резолвим его по таймауту:

const wait = delay => new Promise(r => setTimeout(r, delay));

Дальше можно сделать асинхронную функцию с циклом:

async function asyncDelayedForEach(data, callback, delay) {
  for (let i = 0; i < data.length;) {
    await callback.call(data, data[i], i, data);
    if (++i < data.length) {
      await wait(delay);
    }
  }
}

Или создавать цепочку промисов в явном виде - каждое следующее действие (обработка элемента массива или задержка) выполняется в then'е предыдущего:

const asyncDelayedForEach = (data, callback, delay) =>
  Array.prototype.reduce.call(
    data,
    (promise, n, i, a) => promise
      .then(() => callback.call(a, n, i, a))
      .then(() => -~i === a.length ? void 0 : wait(delay)),
    Promise.resolve()
  );
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

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