Недавно я в отчаянии погуглил около 50 вариантов вышеуказанного названия, так как потратил слишком много времени, пытаясь решить то, что казалось простой задачей. Я пишу это сейчас, чтобы вы, прекрасный программист, который нашел это, могли решить эту простую проблему с таким же простым решением.

Я работал над проектом, в котором пытался получить статистику игрока NBA из API и отобразить ее для пользователя. Цель заключалась в том, чтобы показать статистику за последние 5 сезонов, чтобы пользователь мог видеть тенденции в каждой статистике за этот период времени и принимать решения о своем фантастическом баскетбольном драфте. Я был и остаюсь единственным человеком в целевой аудитории этого приложения.

Для получения статистики потребовалось 5 вызовов API, по одному на каждый год анализа. Я решил, что простой цикл For для каждого года поможет, поэтому я использовал следующий код:

По сути, я выполнял запрос GET для каждого года статистики в цикле For Loop и сохранял его в одном объекте. Единственная проблема заключалась в том, что я возвращал результаты в неправильном порядке.

Не только неправильный порядок, но каждый раз новый и случайный порядок. Это очень огорчило Джереми (меня).

Когда приведенный выше код запускается, JavaScript создает обещание для каждого запроса на выборку, и когда эти обещания выполняются, полученные данные добавляются в мой объект. Это хорошо, это то, чего хочет Джереми. Проблема в том, что все это происходит очень быстро, и цель JavaScript не в том, чтобы вернуть вам каждое промис по порядку, а в том, чтобы вернуть их все как можно скорее. Следовательно, какой бы GET ни был завершен первым, он будет добавлен к объекту первым и так далее.

Все эти промисы выполняются… подождите… асинхронно

Это означает, что все они работают одновременно. Каждый раз, когда я вызывал getStats в своем цикле, создавался новый промис, и все эти промисы выполнялись одновременно.

Что такое обещание

Чтобы действительно понять решение нашей проблемы, нам сначала нужно понять, что такое промис. JavaScript — синхронный язык (пока это не так). Это означает, что код выполняется последовательно; мы вызываем функцию, и эта функция запускается строка за строкой, если она встречает функцию внутри этой функции, она переходит к этой функции и выполняет ее строка за строкой. и так далее. Обещание нарушает эту последовательность. Примером в нашем коде является запрос на выборку. Запрос на выборку требует времени; нам нужно перейти к нашему API, собрать некоторые данные и вернуть их. JavaScript хочет быть эффективным и поэтому не ждет завершения этого трудоемкого процесса, прежде чем он запустит остальную часть нашего кода. Из-за этого, когда мы запускаем fetch, JavaScript создает промис, и это именно то, на что это похоже. Мы обещаем, что скоро у нас будет эта информация, но до тех пор, пожалуйста, продолжайте выполнять наш код.

Это означает, что в нашем цикле мы разветвляем наш код на 5 отдельных стеков выполнения, работающих одновременно. На первой итерации мы говорим JS получить данные за 2017 год. Пока он извлекает эти данные в отдельный стек выполнения, цикл продолжается до следующей итерации, и мы переходим к выборке данных за 2018 год и т. д., создавая дополнительные стеки как мы идем. Когда один из этих стеков завершится, он поместит эти данные в наш объект, но мы не можем контролировать порядок завершения этих итераций, даже если они начинались по порядку.

Чтобы исправить это, нужно сообщить JavaScript, что я хочу, чтобы он дождался выполнения промиса, прежде чем продолжить выполнение цикла и перейти к следующему промису.

Асинхронно/ожидание

К счастью, Javascript дал нам возможность сделать это с помощью async/await. Мы можем реорганизовать мой предыдущий код, чтобы он выглядел так:

Единственное отличие заключается в добавлении ключевого слова async при определении функции и ключевого слова await перед запросом на выборку. Это говорит JS дождаться обещания выборки, прежде чем продолжить выполнение, поэтому мой цикл не будет продолжаться до тех пор, пока первый запрос API не будет завершен и его данные не будут добавлены в мой объект.

Сделав это, мои данные будут введены в мой объект в правильном порядке, и я смогу более эффективно использовать эти данные в своем приложении.

Это может быть довольно запутанным. Когда мы думаем о том, как работает JavaScript, мы обычно думаем о нем как о синхронном, что означает, что все происходит в порядке стека выполнения, который мы построили в нашем коде. Однако, как только мы начнем работать с промисами, все может пойти наперекосяк. Промисы разбивают наш код на асинхронные части, и может быть трудно отслеживать, что и когда происходит. Async/Await — это один из способов отслеживать, когда и как выполняются эти части.

Честно говоря, я не эксперт в этом, но я надеюсь, что если вы были в той же лодке, что и я, и просто хотели, чтобы все оставалось в том порядке, в котором вы их планировали, это помогло вам. Отсюда, теперь, когда вы знаете некоторые из этих ключевых слов и то, что на самом деле пошло не так в вашем коде, надеюсь, вам будет легче найти больше ответов на ваши проблемы. Удачного кодирования!