Предположим, что по какой-то причине мы обходим массив с помощью метода map()
и нам нужно запустить асинхронную функцию на каждом из элементов. Что-то вроде следующего:
const users = ['user1', 'user2', 'user3']
const data = users.map(async (user) => await fetchApiData(user))
Здесь нам нужно понять, что фиктивная функция fetchApiData
(которая получает в качестве параметра имя одного из пользователей) будет осуществлять асинхронный вызов внешнего API, с которым работает наше приложение.
Что произойдет, если мы теперь запишем содержимое переменной data
через консоль? Ну, мы найдем что-то вроде следующего:
const users = ['user1', 'user2', 'user3']
const data = users.map(async (user) => await fetchApiData(user))
console.log(data)
/*
[
Promise { <pending> },
Promise { <pending> },
Promise { <pending> }
]
*/
То есть, выполнение кода не останавливается в ожидании результатов вызова внешнего API, и поэтому данные массива будут образованы таким количеством элементов, сколько пользователей мы объявили в массиве users
и связали с каждой из позиций объект JavaScript Promise
в состоянии ожидания.
Разрешение всех вызовов параллельно.
Первый вариант решения этой проблемы – использовать метод all()
объекта Promise
JavaScript, который позволит всем обещаниям, которые он получает в качестве параметра (этот метод ожидает получить в качестве параметра массив обещаний, которые необходимо разрешить), выполняться параллельно, не завися друг от друга, и не завершит свое выполнение, пока все эти обещания не будут выполнены.
const users = ['user1', 'user2', 'user3']
const data = await Promise.all(
users.map(async (user) => await fetchApiData(user))
)
console.log(data)
/*
[
dataFromUser1,
dataFromUser2,
dataFromUser3
]
*/
При параллельном выполнении мы должны понимать, что общее время выполнения метода будет соответствовать тому обещанию, которое потребляет больше времени на разрешение, что делает его очень быстрой альтернативой, когда нет зависимости между обещаниями.
Последовательное разрешение пламени.
Но что произойдет в случае, если у нас есть зависимость в выполнении обещаний, то есть, что вызовы асинхронной функции (в нашем примере внешний API будет зависеть от результата предыдущего вызова)? В этом случае мы должны использовать структуру для ... из
следующим образом:
const users = ['user1', 'user2', 'user3']
const data = []
for (const user of users) {
data.push(await fetchApiData(user))
}
console.log(data)
/*
[
dataFromUser1,
dataFromUser2,
dataFromUser3
]
*/
В этом случае легко понять, что, поскольку один вызов зависит от предыдущего, результатом выполнения всего кода будет сумма разрешения каждого из обещаний в отдельности.