Ожидает ли функция 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 и присоединитесь к нашему Коллективу талантов.