Для начала давайте взглянем на polyfill метода. На официальной странице developer.mozilla.org реализация достаточно подробно описывает всю суть данного метода. Если опустить все проверки на существование тех или иных объектов в контексте текущего браузера и стандарта, то можно написать примерно такой метод, выделив основные действия:
1 2 3 4 |
Array.prototype.forEach = function (callback) { for (var i = 0; i < this.length; i++) callback(this[i], i, this); }; |
В данном примере отсутствует проверка на контекст. В качестве аргумента у нас выступает только callback.
РЕКОМЕНДУЕМ:
Бесплатные общедоступные CDN для jQuery, Bootstrap, JavaScript
После чего инициализируем массив и напишем метод, который будет симулировать fetch запрос. Для простоты я решил создать массив чисел. Функция «stubFetch» принимает два аргумента: первый — элемент массива, второй — время в миллисекундах. Promise возвращает setTimeout, который просто выводит значения в консоль.
1 2 3 4 5 6 7 8 9 10 |
let stubArr = [1, 2, 3] function stubFetch(value, time) { return new Promise(resolve => { setTimeout(() => { console.log(value) resolve(true) }, time) }) } |
Применим нативный метод.
1 2 3 4 5 |
stubArr.forEach(async (item, index) => { console.log('foo') await stubFetch(value, index * 1000) console.log('bar') }) |
В консоли мы увидим вывод фразы «foo» на каждой итерации, а «bar» в контексте данного решения не имеет смысла. А что, если мы хотим просмотреть ответ сервера и провести какие-то DOM-манипуляции? Или запушить его в массив ответов например? В данном случае достаточно сделать callback асинхронным.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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')) |
Все три варианта использования асинхронного forEach делают абсолютно одно и тоже. Все зависит от стандартов компании, от личных предпочтений, ну и конечно же от поддержки async/await.
РЕКОМЕНДУЕМ:
Как написать безопасный код на JavaScript
Конечно же, данным постом я не открыл Америку, но для возможных дискуссий будет в самый раз.