Автор оригинала: Fredrik Strand Oseberg.
Когда фиксируется асинхронная функция? И почему это такой тяжелый вопрос, чтобы ответить?
Нужно оказывается, что понимание асинхронных функций требует много знаний о том, как JavaScript работает в основном.
Давайте исследуем эту концепцию и узнайте много о JavaScript в процессе.
Вы готовы? Пойдем.
Что такое асинхронный код?
По дизайну JavaScript – это синхронный язык программирования. Это означает, что при выполнении кода JavaScript начинается в верхней части файла и работает через строку кода по строке, пока это не сделано.
Результатом этого решения о проектировании состоит в том, что только одна вещь может произойти в любое время.
Вы можете думать об этом, как будто вы жонглировали шесть небольших шаров. Пока вы жонглируете, ваши руки заняты и не могут справиться с чем-либо еще.
Это то же самое с JavaScript: после того, как код работает, у него полны руки с этим кодом. Мы называем это таким видом синхронного кода блокировка Отказ Потому что это эффективно блокирует другой код.
Давайте вернемся к примеру жонглирования. Что произойдет, если вы хотите добавить еще один мяч? Вместо шести шаров вы хотели жонглировать семь шаров. Это может быть проблемой.
Вы не хотите останавливать жонглирование, потому что это просто так весело. Но вы тоже не можете пойти и получить еще один мяч, потому что это будет означать, что вам нужно было остановиться.
Решение? Делегировать работу другу или члену семьи. Они не жонглируют, поэтому они могут пойти и получить для вас мяч, а затем бросьте его в жонглирование в то время, когда твоя рука свободна, и вы готовы добавить еще один мяч среднего жонглирования.
Это то, что асинхронный код. JavaScript делегирует работу кое-что еще, а затем идет об этом собственном бизнесе. Затем, когда он готов, он получит результаты от работы.
Кто делает другую работу?
Хорошо, поэтому мы знаем, что JavaScript синхронно и ленивый. Это не хочет делать всю работу самой работы, поэтому она настроен на что-то еще.
Но кто этот таинственный объект, который работает на JavaScript? И как он нанят на работу для JavaScript?
Ну, давайте посмотрим на пример асинхронного кода.
const logName = () => { console.log("Han") } setTimeout(logName, 0) console.log("Hi there")
Запуск этого кода приводит к следующему выходу в консоли:
// in console Hi there Han
Хорошо. Что здесь происходит?
Оказывается, так, как мы выходим на работу в JavaScript, это использовать функции, специфичные для окружающей среды и API. И это источник великого путаницы в JavaScript.
JavaScript всегда работает в среде.
Часто эта среда является браузером. Но это также может быть на сервере с Nodejs. Но что на земле разница?
Разница – и это важно – это то, что браузер и сервер (Nodejs), функциональные возможности, не эквивалентны. Они часто похожи, но они не одинаковы.
Давайте проиллюстрируем это при примере. Допустим, JavaScript является главным героем эпической фантазии. Просто обычный малыш фермы.
Теперь, давайте скажем, что этот малыш фермы нашел два костюма специальной брони, который дал им силы за пределами своих собственных.
Когда они использовали браузерный костюм брони, они получили доступ к определенному набору возможностей.
Когда они использовали Server Subs Armor, они получили доступ к другому набору возможностей.
Эти костюмы имеют некоторые перекрытие, потому что создатели этих костюмов были одинаковые потребности в определенных местах, но не в других.
Это то, что является окружение. Место, где работает код, где существуют инструменты, которые построены сверху существующего языка JavaScript. Они не являются частью языка, но линия часто размыта, потому что мы используем эти инструменты каждый день, когда мы пишем код.
Сетримс , извлекать и Дом все примеры веб-API. (Вы можете Смотрите полный список веб-API здесь. ) Это инструменты, которые встроены в браузер, и которые предоставляются нам, когда наш код запущен.
И потому, что мы всегда запускаем JavaScript в среде, похоже, что это часть языка. Но они нет.
Поэтому, если вы когда-нибудь задавались вопросом, почему вы можете использовать Fetch в JavaScript, когда вы запускаете его в браузере (но нужно установить пакет, когда вы запускаете его в Nodejs), именно поэтому. Кто-то подумал, что Fetch была хорошей идеей и построила его как инструмент для среды Nodejs.
Запутанный? Да!
Но теперь мы, наконец, можем понять, что занимает работу от JavaScript, и как она нанята.
Оказывается, это среда, которая берет на себя работу, и способ получения среды выполнять эту работу, – это использовать функциональность, принадлежащие к окружающей среде. Например извлекать или сентиментальный в среде браузера.
Что происходит с работой?
Большой. Таким образом, окружающая среда занимает работу. И что?
В какой-то момент вам нужно вернуть результаты. Но давайте подумаем о том, как это будет работать.
Давайте вернемся к примеру жонглирования с самого начала. Представьте, что вы попросили нового мяча, и друг только что начал бросать на вас мяч, когда вы не были готовы.
Это было бы катастрофой. Может быть, вы могли бы повезло и поймать его и эффективно получить его в свою рутину. Но есть большой шанс, что это может привести к тому, что вы бросили все свои шары и потерпели крах своей рутины. Разве это не было бы лучше, если вы дали строгие инструкции, когда принять мяч?
Как получается, существуют строгие правила, окружающие, когда JavaScript может получить делегированную работу.
Эти правила регулируются петлей событий и включают в себя очередь MicroTask и Macrotask. Да, я знаю. Это много. Но нести со мной.
Хорошо. Поэтому, когда мы делегируем асинхронный код в браузер, браузер берет и запускает код и принимает эту рабочую нагрузку. Но могут быть несколько задач, которые даны браузеру, поэтому нам нужно убедиться, что мы можем приоритетировать эти задачи.
Вот где в пьесе входит очередь микрозарки и макрозаска. Браузер возьмет на работу, сделайте это, затем поместите результат в одну из двух очередей на основе типа работы, которую он получает.
Например, обещания размещены в очереди MicroTask и имеют более высокий приоритет.
События и поселки являются примерами работы, которая помещается в очередь макротасных средств и имеет более низкий приоритет.
Теперь, как только работа будет сделана, и помещается в одну из двух очередей, цикл событий будет работать вперед и назад и проверять, готов ли JavaScript, готов получить результаты.
Только когда JavaScript выполняется выполнение всего его синхронного кода, и является хорошим и готовым, будет ли петлю события начнет выбирать из очередей и передавать функции обратно к JavaScript для запуска.
Итак, давайте посмотрим на пример:
setTimeout(() => console.log("hello"), 0) fetch("https://someapi/data").then(response => response.json()) .then(data => console.log(data)) console.log("What soup?")
Что будет здесь заказ?
- Во-первых, Settimeout делегирован в браузер, который выполняет работу и ставит результирующую функцию в очереди макрота.
- Во-вторых, привлечение делегируется в браузере, который принимает работу. Он извлекает данные с конечной точки и ставит полученные функции в очереди MicroTask.
- JavaScript выходит из журналов «Какой суп»?
- Контур событий проверяет, готов ли JavaScript, чтобы получить результаты по очереди.
- Когда выполняется Console.log, JavaScript готов. Контур событий выбирает очередные функции функций из очереди MicroTask, который имеет более высокий приоритет и дает им обратно в JavaScript для выполнения.
- После того, как Queue MicroTask является пустой, обратный вызов Settimeout вынимается из очереди Macrotask и возвращает JavaScript для выполнения.
In console: // What soup? // the data from the api // hello
Обещания
Теперь вы должны иметь большое значение знания о том, как асинхронный код обрабатывается JavaScript и средой браузера. Так что давайте поговорим о обещаниях.
Обещание – это конструкция JavaScript, которая представляет собой будущее неизвестное значение. Концептуально обещание – просто JavaScript, обещая вернуть ценность . Это может быть результатом из вызова API, или это может быть объектом ошибок из неудачной сети запроса. Вы гарантированно что-то получите.
const promise = new Promise((resolve, reject) => { // Make a network request if (response.status === 200) { resolve(response.body) } else { const error = { ... } reject(error) } }) promise.then(res => { console.log(res) }).catch(err => { console.log(err) })
Обещание может иметь следующие государства:
- Выполнено – действие успешно завершено
- отклонено – действие не удалось
- Ожидание – ни одно действие завершено
- урегулированный – был выполнен или отклонен
Обещание получает разрешую и функцию отклонения, которую можно призвать, чтобы вызвать одно из этих состояний.
Одной из больших точек продажи обещаний является то, что мы можем цепит функции, которые мы хотим случиться на успехе (разрешать) или сбой (отклонить):
- Зарегистрировать функцию, чтобы запустить успех, мы используем.
- Чтобы зарегистрировать функцию, чтобы запустить сбой мы используем .catch
// Fetch returns a promise fetch("https://swapi.dev/api/people/1") .then((res) => console.log("This function is run when the request succeeds", res) .catch(err => console.log("This function is run when the request fails", err) // Chaining multiple functions fetch("https://swapi.dev/api/people/1") .then((res) => doSomethingWithResult(res)) .then((finalResult) => console.log(finalResult)) .catch((err => doSomethingWithErr(err))
Идеально. Теперь давайте посмотрим, как это выглядит под капотом, используя пример в качестве примера:
const fetch = (url, options) => { // simplified return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() // ... make request xhr.onload = () => { const options = { status: xhr.status, statusText: xhr.statusText ... } resolve(new Response(xhr.response, options)) } xhr.onerror = () => { reject(new TypeError("Request failed")) } } fetch("https://swapi.dev/api/people/1") // Register handleResponse to run when promise resolves .then(handleResponse) .catch(handleError) // conceptually, the promise looks like this now: // { status: "pending", onsuccess: [handleResponse], onfailure: [handleError] } const handleResponse = (response) => { // handleResponse will automatically receive the response, ¨ // because the promise resolves with a value and automatically injects into the function console.log(response) } const handleError = (response) => { // handleError will automatically receive the error, ¨ // because the promise resolves with a value and automatically injects into the function console.log(response) } // the promise will either resolve or reject causing it to run all of the registered functions in the respective arrays // injecting the value. Let's inspect the happy path: // 1. XHR event listener fires // 2. If the request was successfull, the onload event listener triggers // 3. The onload fires the resolve(VALUE) function with given value // 4. Resolve triggers and schedules the functions registered with .then
Таким образом, мы можем использовать обещания делать асинхронную работу, и быть уверенным, что мы можем справиться с любым результатом из этих обещаний. Это ценное предложение. Если вы хотите узнать больше о обещаниях, вы можете прочитать больше о них здесь и здесь Отказ
Когда мы используем обещания, мы цепим наши функции на обещание справиться с разными сценариями.
Это работает, но нам все еще нужно обрабатывать нашу логику внутри обратных вызовов (вложенные функции), как только мы получим наши результаты. Что если бы мы могли использовать обещания, но напишите синхронный код? Оказывается, мы можем.
Async/a ждать
Async/a ждать – это способ написания обещаний, которые позволяют нам написать асинхронный код в синхронном виде. Давайте посмотрим.
const getData = async () => { const response = await fetch("https://jsonplaceholder.typicode.com/todos/1") const data = await response.json() console.log(data) } getData()
Ничто не изменилось под капотом здесь. Мы все еще используем обещания, чтобы получить данные, но теперь это выглядит синхронно, и у нас больше нет. Затем блоки .Catch.
Async/a a a a a a a a enae – это просто синтаксический сахар, обеспечивающий способ создания кода, который легче для рассуждения, без изменения нижней динамики.
Давайте посмотрим, как это работает.
Async/ждут, позволяет нам использовать Генераторы к Пауза выполнение функции. Когда мы используем Async/ждут, мы не блокируем, потому что функция дает контроль обратно в основную программу.
Затем, когда обещание решает, мы используем генератор, чтобы дать контроль обратно в асинхронную функцию со значением из разрешенного обещания.
Вы можете прочитать больше здесь для отличного обзора генераторов и асинхронного кода.
По сути, теперь мы можем написать асинхронный код, который выглядит как синхронный код. Что означает, что о том, что все легче рассуждать, и мы можем использовать синхронные инструменты для обработки ошибок, таких как TRY/CALL:
const getData = async () => { try { const response = await fetch("https://jsonplaceholder.typicode.com/todos/1") const data = await response.json() console.log(data) } catch (err) { console.log(err) } } getData()
Хорошо. Так как мы его используем? Для того, чтобы использовать Async/ждут, нам нужно добавить функцию с async. Это не делает его асинхронной функцией, она просто позволяет нам использовать ждут внутри него.
Неспособность предоставить ключевое слово Async, приведет к ошибке синтаксиса при попытке использования ждут ange внутри обычной функции.
const getData = async () => { console.log("We can use await in this function") }
Из-за этого мы не можем использовать Async/ждут в коде верхнего уровня. Но async и a ждать все еще просто синтаксические сахарные обещания. Таким образом, мы можем обрабатывать случаи высших уровней с цепочкой обещания:
async function getData() { let response = await fetch('http://apiurl.com'); } // getData is a promise getData().then(res => console.log(res)).catch(err => console.log(err);
Это разоблачает еще один интересный факт о Async/ждут. При определении функции ASYNC Это всегда будет вернуть обещание.
Использование Async/ждут, может показаться магией сначала. Но, как и любая магия, это просто достаточно передовые технологии, которые развивались в течение многих лет. Надеюсь, теперь у вас есть солидная хватка оснований, и может использовать Async/ждать с уверенностью.
Если вы сделали это здесь, поздравляю. Вы только что добавили ключевую часть знания о JavaScript и как он работает с его средами на ваш панель инструментов.
Это определенно запутанному предмету, а линии не всегда ясны. Но теперь вы, надеюсь, понять, как JavaScript работает с асинхронным кодом в браузере, а более сильный захват как обещаний, так и aSync/ждут.
Если вам понравилось эту статью, вы также можете наслаждаться моим YouTube канал . У меня сейчас есть Серия веб-основателей идти туда, куда я прохожу Http. , Строительные веб-серверы с нуля и более.
Есть также серия, идущая на Создание всего приложения с React , если это ваше варенье. И я планирую добавить гораздо больше контента здесь, в будущем, идущем в глубине в темах JavaScript.
И если вы хотите сказать привет или пообщаться о веб-разработке, вы всегда можете добраться до меня в Twitter в @Foseberg. Спасибо за прочтение!
Оригинал: “https://www.freecodecamp.org/news/async-await-javascript-tutorial/”