Это не асинхронный.Это блокировка.Те, кто сначала выучил язык, такой как Java, C или Python, прежде чем попробовать JS, запутаются, когда попытаются добавить произвольную задержку или вызов API в их теле цикла.
Скажем, вы попробовали это:*
const array = [1, 2, 3, 4, 5];
array.forEach((el, i) => {
setTimeout(() => {
console.log(el);
}, 1000);
});
Код выполняется по порядку, и следующая итерация цикла не начинает выполняться, пока предыдущая не прошла свою последнюю строку.
Вы, вероятно, ожидаете, что setTimeout задержит выполнениепока не истечет время вашей задержки.Это не так, потому что метод setTimeout фактически возвращает значение немедленно.В Node.js он возвращает объект Timeout, а в браузере возвращает число, указывающее на экземпляр timeout.
Когда что-то возвращается, начинается выполнение следующей строки.Таким образом, вы получите этот эффект, когда программа выполняется чуть более 1 секунды, и перед закрытием она выдает 5 консольных журналов почти одновременно.
Если вы хотите, чтобы время ожидания заставило цикл ждать, покаего задержка прошла, вы можете использовать следующий код:
function forEachWithCallback(callback) {
const arrayCopy = this;
let index = 0;
const next = () => {
index++;
if (arrayCopy.length > 0) {
callback(arrayCopy.shift(), index, next);
}
}
next();
}
Array.prototype.forEachWithCallback = forEachWithCallback;
const array = [1, 2, 3, 4, 5];
array.forEachWithCallback((el, i, next) => {
setTimeout(() => {
console.log(el);
next();
}, 1000);
});
Вместо использования собственного метода forEach, который поставляется с массивами JS, вы можете добавить свой собственный с обратным вызовом.Использование этого заставит ваши итерации ждать истечения времени ожидания их предшественника.Следующая итерация не может начаться до тех пор, пока в теле вашего цикла не будет вызван «следующий» метод.Таким образом, выполнение этого кода займет чуть более 5 секунд, и один раз в секунду будет один файл console.log.
Это хорошо работает и с JS Promises, например, когда вы хотите выполнить ajax.
// "request" implementation can be found in the link at the bottom of this answer
const array = [1, 2, 3, 4, 5];
array.forEachWithPromise((el, i, next) => {
request({
method: 'GET',
hostname: 'httpbin.org',
path: '/get?myArg=' + el
}).then((res) => {
const responseBody = JSON.parse(res.body);
console.log(responseBody.args.myArg);
next();
}).error((err) => {
console.error(err);
});
});
Здесь вы найдете множество свободного кода, который вы можете использовать как в браузере, так и в Node.js для создания циклов for-each, без внешних пакетов или зависимостей.https://gist.github.com/ajb413/d55489eec64db0bb4079a8d7af733aab