Ожидает ли функция Array.prototype.forEach() только синхронную функцию?

Глядя на код ниже:
async function displayScores() {
const scores = [1, 2, 3, 4, 5];
console.log("Starting to display scores");
scores.forEach((score) => {
console.log('The current score is ', score);
});
console.log("Finished displaying scores. This should execute last!");
}
displayScores();
Этот код даст следующий результат:
Starting to display scores The current score is 1 The current score is 2 The current score is 3 The current score is 4 The current score is 5 Finished displaying scores. This should execute last!
Однако изменение кода с помощью некоторой асинхронной функции:
function myFunction(value) {
return new Promise((resolve) => {
console.log("My extra function is running");
resolve();
});
}
async function displayScores() {
const scores = [1, 2, 3, 4, 5];
console.log("Starting to display scores");
scores.forEach(async (score) => {
console.log('Before the async function:');
await myFunction()
console.log('The current score is ', score);
});
console.log("Finished displaying scores. This should execute last!");
}
displayScores();
Вы ожидаете, что Finished отобразит баллы. Это должно выполняться последним! по-прежнему печататься последним, поскольку forEach является синхронным.
На самом деле это вывод: 🤯
Starting to display scores Before the async function: My extra function is running Before the async function: My extra function is running Before the async function: My extra function is running Before the async function: My extra function is running Before the async function: My extra function is running Finished displaying scores. This should execute last! The current score is 1 The current score is 2 The current score is 3 The current score is 4 The current score is 5
Я узнал об этом, когда это вызвало ошибку в веб-приложении, над которым я работал.
Я понял, что использование async/await с forEach приводит к неожиданному поведению. Хотя кажется, что ключевое слово await выполняет свою работу, цикл forEach не ожидает обещания, когда он переходит к следующему циклу.
Мое понимание неожиданного поведения может быть недостаточно ясным, постарайтесь прокомментировать свои мысли по этому поводу.
Несмотря на это, я обнаружил, что это решение работает.
Прибегнуть к использованию базового цикла for, for(;;;) и for…of — отлично сработали.

Еще одно работающее решение — использование Array.map вместе с Promise.all() как таковое:
await Promise.all(
scores.map(async (score) => {
console.log('Before the async function:');
await myFunction()
console.log('The current score is ', score);
})
);
// This works perfectly.
OUTPUT:
Starting to display scores
Before the async function:
My extra function is running
Before the async function:
My extra function is running
Before the async function:
My extra function is running
Before the async function:
My extra function is running
Before the async function:
My extra function is running
The current score is 1
The current score is 2
The current score is 3
The current score is 4
The current score is 5
Finished displaying scores. This should execute last!

Поделитесь своими мыслями и опытом в разделе комментариев.
Спасибо! 👍
Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter и LinkedIn. Посетите наш Community Discord и присоединитесь к нашему Коллективу талантов.