Как дождаться асинхронной функции ?(javascript)
Проблема в том, что 2й цикл с arr2 начинает работу до того, как закончит первый цикл, а arr2.push(z) до того, как z получит результат. Как исправить ?
Отслеживать
14.5k 6 6 золотых знаков 33 33 серебряных знака 71 71 бронзовый знак
задан 3 окт 2020 в 23:21
138 10 10 бронзовых знаков
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Если хочется параллельно запустить несколько асинхронных функций и дождаться их результата, то лучше использовать Promise.all и arr.map. forEach здесь никак не подходит.
Пример кода, Который демонстрирует эту идею:
arr = [7, 2, 8, 4, 3]; Promise.all(arr.map(async function(item, i) < var z = await func(item); // операции над z return z; >)).then(arr2 => < arr2.forEach(function(item, i) < console.log(item); >); >)
Как дождаться выполнения асинхронной функции для изменения стейта в React?
есть асинхронный метод, который получает дату и есть стейт-массив, от которого зависит отрисовка всего другого. как дождаться ответа от getData в данном случае?
const App = async () => < const [noteArr, setNoteArr] = useState([]) setNoteArr(getData()) useEffect(() => < return () =>< console.log(noteArr); >; >, [noteArr]); return ( setNoteArr=/> ); >
- Вопрос задан более года назад
- 1014 просмотров
1 комментарий
Простой 1 комментарий
А ничего, что ты изменяешь стейт внутри тела компонента?
Решения вопроса 1
Асинхронные функции должны вызываться в useEffect в таком случае. Поместите setNoteArr(getData()) в useEffect с пустыми зависимостями [] и он будет вызываться при монтировании компонента.
Вообще ваш компонент должен выглядеть так:
const App = () => < const [noteArr, setNoteArr] = useState([]) useEffect(() => < (async () =>< const result = await getData(); setNoteArr(result); >)() >, []); useEffect(() => < return () =>< console.log(noteArr); >; >, [noteArr]); return ( setNoteArr=/> ); >
Тогда все будет работать как надо и читаемость улучшится
Ответ написан более года назад
Комментировать
Нравится 1 Комментировать
Ответы на вопрос 1

Дмитрий Воробьев @CriticalError
Ваш ответ не совсем корректен, так как данный способ не заставляет дожидаться выполнения асинхронной функции, если поставите debagger слазу после
useEffect(() => < (async () =>< const result = await getData(); setNoteArr(result); >)() >, []);
Async/await
Существует специальный синтаксис для работы с промисами, который называется «async/await». Он удивительно прост для понимания и использования.
Асинхронные функции
Начнём с ключевого слова async . Оно ставится перед функцией, вот так:
async function f()
У слова async один простой смысл: эта функция всегда возвращает промис. Значения других типов оборачиваются в завершившийся успешно промис автоматически.
Например, эта функция возвратит выполненный промис с результатом 1 :
async function f() < return 1; >f().then(alert); // 1
Можно и явно вернуть промис, результат будет одинаковым:
async function f() < return Promise.resolve(1); >f().then(alert); // 1
Так что ключевое слово async перед функцией гарантирует, что эта функция в любом случае вернёт промис. Согласитесь, достаточно просто? Но это ещё не всё. Есть другое ключевое слово – await , которое можно использовать только внутри async -функций.
Await
// работает только внутри async–функций let value = await promise;
Ключевое слово await заставит интерпретатор JavaScript ждать до тех пор, пока промис справа от await не выполнится. После чего оно вернёт его результат, и выполнение кода продолжится.
В этом примере промис успешно выполнится через 1 секунду:
async function f() < let promise = new Promise((resolve, reject) => < setTimeout(() =>resolve("готово!"), 1000) >); let result = await promise; // будет ждать, пока промис не выполнится (*) alert(result); // "готово!" > f();
В данном примере выполнение функции остановится на строке (*) до тех пор, пока промис не выполнится. Это произойдёт через секунду после запуска функции. После чего в переменную result будет записан результат выполнения промиса, и браузер отобразит alert-окно «готово!».
Обратите внимание, хотя await и заставляет JavaScript дожидаться выполнения промиса, это не отнимает ресурсов процессора. Пока промис не выполнится, JS-движок может заниматься другими задачами: выполнять прочие скрипты, обрабатывать события и т.п.
По сути, это просто «синтаксический сахар» для получения результата промиса, более наглядный, чем promise.then .
await нельзя использовать в обычных функциях
Если мы попробуем использовать await внутри функции, объявленной без async , получим синтаксическую ошибку:
async / await
Ждать выполнения асинхронного кода стало легче! Больше никаких колбэков и промисов, только новые ключевые слова.
Время чтения: меньше 5 мин
Открыть/закрыть навигацию по статье
- Кратко
- Как понять
- На практике
- Николай Лопин советует
- Алексей Орлов советует
Обновлено 21 июля 2022
Эта документация связана с понятием асинхронности в JavaScript. Зачем нужен асинхронный код и как он работает в деталях описано в обзорной статье Асинхронность в JS.
Кратко
Скопировать ссылку «Кратко» Скопировано
Добавленное перед определением функции ключевое слово async делает функцию асинхронной. Возвращаемое значение такой функции автоматически оборачивается в Promise:
async function getStarWarsMovies() return 1> console.log(getStarWarsMovies()) // Promise < : "fulfilled", : 1 >async function getStarWarsMovies() return 1 > console.log(getStarWarsMovies()) // Promise < : "fulfilled", : 1 >Асинхронные функции нужны для выполнения асинхронных операций: работой с API, базами данных, чтения файлов и т.д.
Асинхронные операции выполняются не сразу: код отправил запрос к API и ждёт, пока сервер пришлёт ответ. Ключевое слово await используется, чтобы дождаться выполнения асинхронной операции:
async function getStarWarsMovie(id) const response = await fetch(`https://swapi.dev/api/films/$/`) console.log("ответ получен", response) // *1 return response.json()> const movies = getStarWarsMovie(1).then((movie) => console.log(movie.title)>) // *2console.log("результат вызова функции", movies) // *3async function getStarWarsMovie(id) const response = await fetch(`https://swapi.dev/api/films/$id>/`) console.log("ответ получен", response) // *1 return response.json() > const movies = getStarWarsMovie(1).then((movie) => console.log(movie.title) >) // *2 console.log("результат вызова функции", movies) // *3Движок JavaScript при этом не блокируется и может выполнять другой код. Как только ответ получен, выполнение кода продолжается.
Вывод на экран будет следующий:
"результат вызова функции" Promise // вызвали функцию, она начала выполнять асинхронную операцию и вернула Promise (*3)"ответ получен" Response // получили ответ API, продолжаем выполнение функции (*1)"A New Hope" // сработал callback (*2)"результат вызова функции" Promise // вызвали функцию, она начала выполнять асинхронную операцию и вернула Promise (*3) "ответ получен" Response // получили ответ API, продолжаем выполнение функции (*1) "A New Hope" // сработал callback (*2)Как понять
Скопировать ссылку «Как понять» Скопировано
Ключевые слова async / await не привносят в JavaScript что-то новое. Они только упрощают работу с Promise.
Вместо кода с цепочкой вызовов:
function getMainActorProfileFromMovie(id) return fetch(`https://swapi.dev/api/films/$/`) .then((movieResponse) => return movieResponse.json() >) .then((movie) => const characterUrl = movie.characters[0].split("//")[1] return fetch(`https://$`) >) .then((characterResponse) => return characterResponse.json() >) .catch((err) => console.error("Произошла ошибка!", err) >)> getMainActorProfileFromMovie(1).then((profile) => console.log(profile)>)function getMainActorProfileFromMovie(id) return fetch(`https://swapi.dev/api/films/$id>/`) .then((movieResponse) => return movieResponse.json() >) .then((movie) => const characterUrl = movie.characters[0].split("//")[1] return fetch(`https://$characterUrl>`) >) .then((characterResponse) => return characterResponse.json() >) .catch((err) => console.error("Произошла ошибка!", err) >) > getMainActorProfileFromMovie(1).then((profile) => console.log(profile) >)Можно записать с async / await :
async function getMainActorProfileFromMovie(id) try const movieResponse = await fetch(`https://swapi.dev/api/films/$/`); const movie = await movieResponse.json(); const characterUrl = movie.characters[0].split('//')[1]; const characterResponse = await fetch(`https://$`); return characterResponse.json(); > catch (err) console.error('Произошла ошибка!', err); >> getMainActorProfileFromMovie(1).then((profile) => );async function getMainActorProfileFromMovie(id) try const movieResponse = await fetch(`https://swapi.dev/api/films/$id>/`); const movie = await movieResponse.json(); const characterUrl = movie.characters[0].split('//')[1]; const characterResponse = await fetch(`https://$characterUrl>`); return characterResponse.json(); > catch (err) console.error('Произошла ошибка!', err); > > getMainActorProfileFromMovie(1).then((profile) => console.log(profile)>);Такой код проще понимать:
- он плоский;
- выглядит, как синхронный;
- использует стандартный try. catch блок для обработки ошибок.
☝️ Ключевое слово await работает только внутри асинхронных функций. Вызов его вне функции будет синтаксической ошибкой:
function getMainActorProfileFromMovie(id) // код примера выше> await getMainActorProfileFromMovie(1)function getMainActorProfileFromMovie(id) // код примера выше > await getMainActorProfileFromMovie(1)Код упадёт с ошибкой SyntaxError : await is only valid in async functions and async generators .
На практике
Скопировать ссылку «На практике» Скопировано
Николай Лопин советует
Скопировать ссылку «Николай Лопин советует» Скопировано
Всегда используйте async / await вместо цепочек then ( ) и колбэков.
Этот подход проще читается, легче отлаживается, пользуется стандартными способами обработки ошибок.
await нельзя использовать вне асинхронных функций. Если нужно выполнить асинхронную операцию в глобальной области видимости, придётся воспользоваться then .
Алексей Орлов советует
Скопировать ссылку «Алексей Орлов советует» Скопировано
Используйте await Promise . all ( [ . . . ] ) для параллельного выполнения нескольких независимых асинхронных функций.
Используя async / await , мы делаем наш код последовательным: ожидаем выполнения одной асинхронной функции и лишь после запускаем другую. В примере ниже новости будут запрошены только после получения пользователя:
async function getUser() // Возвращает информацию о пользователе> async function getNews() // Возвращает список новостей> const user = await getUser()const news = await getNews()async function getUser() // Возвращает информацию о пользователе > async function getNews() // Возвращает список новостей > const user = await getUser() const news = await getNews()Но, запустив get News параллельно c get User , мы в большинстве случаев получим результат быстрее. Promise . all ( ) позволяет запустить запросы параллельно, при этом дожидаться результата мы можем как и раньше при помощи await :
const [user, news] = await Promise.all([ getUser(), getNews()])const [user, news] = await Promise.all([ getUser(), getNews() ])Не смешивайте синтаксис async / await и Promise . then , старайтесь применять один подход на проекте: так код легче читать и поддерживать.
