Pull to refresh

Асинхронный forEach

Асинхронный forEach


Первоначально давайте взглянем на polyfill метода. На сайте developer.mozilla.org реализация достаточно подробно описывает всю суть данного метода. Если опустить все проверки на существование тех или иных объектов в контексте текущего браузера и стандарта, то можно написать примерно такой метод, выделив основные действия:

Array.prototype.forEach = function (callback) {
  for (var i = 0; i < this.length; i++) 
    callback(this[i], i, this);
};

В данном примере отсутствует проверка на контекст. В качестве аргумента у нас выступает только callback.

Далее мы инициализируем массив и напишем метод, который будет симулировать fetch запрос. Для простоты я решил создать массив чисел. Функция «stubFetch» принимает два аргумента: первый — элемент массива, второй — время в миллисекундах. Promise возвращает setTimeout, который просто выводит значения в консоль.

let stubArr = [1, 2, 3]

function stubFetch(value, time) {
  return new Promise(resolve => {
    setTimeout(() => {  
      console.log(value)
      resolve(true) 
    }, time)
  })
}

Попробуем применить нативный метод.

stubArr.forEach(async (item, index) => {
  console.log('foo')
  await stubFetch(value, index * 1000)
  console.log('bar')
})

image

В консоли мы увидим вывод фразы «foo» на каждой итерации, а «bar» в контексте данного решения не имеет смысла. А что, если мы хотим просмотреть ответ сервера и провести какие-то DOM-манипуляции? Или запушить его в массив ответов например? В данном случае достаточно сделать callback асинхронным.

async function asyncForEach(arr, callback) {
  for(let i = 0; i < arr.length; i++)
    await callback(arr[i], i, arr) 
}

// 1ый вариант использования
asyncForEach(stubArr, async (value, index) => {
  await stubFetch(value, index * 1000)
}).then(_ => console.log('Finish'))

// 2й вариант использования
async function index() {
  await asyncForEach(stubArr, async (value, index) => {
    await stubFetch(value, index * 1000)
  }) 
  console.log('Finish')
}
index()

// 3ий вариант использования
Promise.all([asyncForEach(stubArr, async (value, index) => {
  await stubFetch(value, index * 1000)
})]).then(_ => console.log('Finish')) 

image

Все три варианта использования асинхронного forEach делают абсолютно одно и тоже. Все зависит от стандартов компании, от личных предпочтений, ну и конечно же от поддержки async/await. Конечно же, данным постом я не открыл Америку, но для возможных дискуссий будет в самый раз.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.