Если вас заинтересовала эта статья, то вы, наверное, несколько разбираетесь в асинхронном программировании на JavaScript и, возможно, интересуетесь, как оно работает в TypeScript.

Поскольку TypeScript – это надмножество JavaScript, async/await там работает точно так же, но с некоторыми дополнительными бонусами и безопасностью типов. TypeScript позволяет запрограммировать безопасность типа ожидаемого результата и даже проверить, нет ли ошибок, связанных с типом. Поэтому баги отлавливаются на ранних стадиях разработки программы.

В сущности, async/await – это синтаксический сахар для промисов, то есть, ключевое слово async/await обертывает промисы. Функция async всегда возвращает промис. Даже если пропустить ключевое слово Promise, компилятор обернет вашу функцию в немедленно разрешаемый промис.

Давайте покажу:

const myAsynFunction = async (url: string): Promise<T> => {
    const { data } = await fetch(url)
    return data
}
const immediatelyResolvedPromise = (url: string) => {
    const resultPromise = new Promise((resolve, reject) => {
        resolve(fetch(url))
    })
    return  resultPromise
}

Пусть они и выглядят совершенно по-разному, два вышеприведенных фрагмента кода более-менее эквивалентны. Async/await просто позволяет писать код в более синхронной манере и избавляет от необходимости встраивать промис в строку. Это очень мощный прием, если имеешь дело со сложными асинхронными паттернами.

Чтобы выжать максимум из синтаксиса async/await, нужно иметь базовое представление о промисах. Давайте подробнее рассмотрим, что представляют собой промисы на фундаментальном уровне.

Что такое промис в TypeScript?

В переводе с английского «promise» означает «обещание». В JavaScript промис описывает ожидание того, что некоторое событие произойдет в определенный момент, и ваше приложение полагается на результат этого будущего события при выполнении определенных других задач.

Чтобы показать, что я имею в виду, разберу реалистичный пример, выражу его в псевдокоде, а затем в действующем коде TypeScript.

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

Заметили паттерн? Первая очевидная вещь, которую нужно отметить – второе событие полностью полагается на первое. Если будет выполнено обещание, заложенное в первом событии, то выполнится и следующее событие. Промис в том событии либо выполняется, либо не выполняется, либо остается в подвешенном состоянии.

Рассмотрим эту последовательность шаг за шагом и выразим ее в коде.

Синтаксис промиса

Прежде, чем написать весь код, давайте разберемся в синтаксисе промиса – конкретно, такого промиса, который разрешается в строку.

Мы объявили promise при помощи ключевого слова new + Promise, где промис принимает аргументы resolve и reject. Теперь давайте напишем промис, выражающий события из вышеприведенной блок-схемы.

// Я отправляю запрос в компанию. Он синхронный
// Компания обещает мне выполнить работу
const angelMowersPromise = new Promise<string>((resolve, reject) => {
    // Обещание разрешилось спустя несколько часов
    setTimeout(() => {
        resolve('We finished mowing the lawn')
    }, 100000) // разрешается спустя 100 000 мс
    reject("We couldn't mow the lawn")
})

const myPaymentPromise = new Promise<Record<string, number | string>>((resolve, reject) => {
    // разрешившийся промис с объектом: платежом в 1000 евро
    // и большое спасибо
    setTimeout(() => {
        resolve({
            amount: 1000,
            note: 'Thank You',
        })
    }, 100000)
    // промис отклонен. 0 евро и отзыв «неудовлетворительно» 
    reject({
        amount: 0,
        note: 'Sorry Lawn was not properly Mowed',
    })
})

В вышеприведенном коде объявлены как обещания компании, так и наши обещания. Обещание компании либо выполняется через 100 000 мс, либо отклоняется. Promise всегда находится в одном из трех состояний: resolved, если ошибки нет, rejected, если встретилась ошибка, или pending, если обещание promise пока ни отклонено, ни выполнено. В нашем случае все это укладывается в период 100000ms.

Но как нам выполнить эту задачу последовательным синхронным образом? Здесь-то и пригодится ключевое слово then. Без него функции просто выполняются в том же порядке, в котором и разрешаются.

Последовательное выполнение с .then

Теперь можно сцепить промисы, что позволяет выполнять их последовательно с применением .then. Эти функции похожи на обычный человеческий язык: сделай так, а затем вот это, а потом то и так далее.

angelMowersPromise
    .then(() => myPaymentPromise.then(res => console.log(res)))
    .catch(error => console.log(error))

Вышеприведенный код выполнит angelMowersPromise. Если с этим ошибки не случится, он выполнит myPaymentPromise. Если в одном из двух промисов возникнет ошибка, то она будет отловлена в блоке catch.

Теперь давайте рассмотрим более технический пример. При программировании клиентского интерфейса есть типичная задача: выполнять запросы по сети и адекватно реагировать на их результаты.

Ниже – запрос, требующий выбрать список сотрудников с удаленного сервера.

const api =  'http://dummy.restapiexample.com/api/v1/employees'
   fetch(api)
    .then(response => response.json())
    .then(employees => employees.forEach(employee => console.log(employee.id)) // логирует id всех сотрудников
    .catch(error => console.log(error.message))) // логирует любую ошибку, приходящую от промиса

Бывает так, что необходимо параллельно или последовательно выполнять сразу множество обещаний. В подобных сценариях особенно полезны такие конструкции как Promise.all или Promise.race.

Представьте, к примеру, сто нужно выбрать список из 1 000 пользователей GitHub, а затем сделать дополнительный запрос с ID, чтобы выбрать для каждого из них аватарки. Совсем не обязательно вы захотите дожидаться завершения этих операций со всеми пользователями в последовательности; вам нужны только все выбранные аватарки. Мы подробнее поговорим об этом ниже, когда будем обсуждать Promise.all.

Теперь, когда вы в общем и целом поняли, что такое промисы, давайте рассмотрим синтаксис async/await.

async/await

Синтаксис Async/await удивительно прост при работе с промисами. Он предоставляет простой интерфейс для чтения и записи промисов, причем, таким образом, что они кажутся синхронными.

Конструкция async/await всегда возвращает Promise. Даже если пропустить ключевое слово Promise, компилятор обернет вашу функцию в немедленно разрешаемый промис. Таким образом, можно трактовать возвращаемое значение функции async как Promise, что довольно полезно, когда нужно разрешать сразу множество асинхронных функций.

Как понятно из названия, async с await всегда ходят парой. То есть, делать await можно только внутри функции async. Функция async сообщает компилятору, что это асинхронная функция.

Если преобразовать вышеприведенные промисы, то получится такой синтаксис:

const myAsync = async (): Promise<Record<string, number | string>> => {
    await angelMowersPromise
    const response = await myPaymentPromise
    return response
}

Сразу заметно, что этот код выглядит более удобочитаемым и кажется синхронным. В строке 3 мы сказали компилятору дожидаться выполнения angelMowersPromise, и только потом делать что-то еще. Затем возвращаем отклик от myPaymentPromise.

Возможно, вы заметили, что здесь мы пропустили обработку ошибок. Это можно было бы сделать в блоке catch после .then в промисе. Но что делать, если нам попадется ошибка? Это приводит нас к блоку try/catch.

Обработка ошибок в try/catch

Вернемся к примеру с выбором записей о сотрудниках, чтобы показать обработку ошибок в действии, поскольку именно при выполнении запроса по сети ошибка вполне может возникнуть.

Допустим, например, что у нас лег сервер, либо что мы отправили запрос в неверном формате. Мы должны приостановить выполнение, чтобы предотвратить обвал программы. Синтаксис будет выглядеть так:

interface Employee {
    id: number
    employee_name: string
    employee_salary: number
    employee_age: number
    profile_image: string
}
const fetchEmployees = async (): Promise<Array<Employee> | string> => {
    const api = 'http://dummy.restapiexample.com/api/v1/employees'
    try {
        const response = await fetch(api)
        const { data } = await response.json()
        return data
    } catch (error) {
        if (error) {
            return error.message
        }
    }
}

Мы инициировали функцию async. В качестве возвращаемого значения ожидаем массив типа typeof с информацией о сотрудниках, либо строку с сообщениями об ошибке. Соответственно, тип Promise формулируется как Promise<Array<Employee> | string>.

В блоке try находятся выражения, которые функция должна выполнять, если ошибок не будет. Блок catch захватывает любую возникающую ошибку. В таком случае мы просто возвращаем свойство message объекта error.

Красота происходящего заключается в том, что любая ошибка, рождающаяся в блоке try, сразу выбрасывается и захватывается блоком catch. Если какое-то исключение ускользнет, то может получиться код, плохо поддающийся отладке, либо даже может быть испорчена вся программа.

Конкурентное выполнение при помощи Promise.all

Как я говорил ранее, бывает, что обещания должны выполняться параллельно.

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

В данном случае мы воспользуемся Promise.all. Как пишет Mozilla, “Promise.all обычно применяется после того, как было запущено множество асинхронных задач, которые должны работать конкурентно, и после того, как пообещали, каковы будут их результаты – чтобы можно было дождаться, пока все эти задачи будут завершены.”

В псевдокоде было бы что-то подобное:

  • Выбрать всех пользователей => /employee

  • Дождаться всех данных о пользователях. Извлечь id от каждого пользователя. Выбрать каждого пользователя => /employee/{id}

  • Сгенерировать электронное сообщение для каждого пользователя по его имени

const baseApi = 'https://reqres.in/api/users?page=1'
const userApi = 'https://reqres.in/api/user'

const fetchAllEmployees = async (url: string): Promise<Employee[]> => {
    const response = await fetch(url)
    const { data } = await response.json()
    return data
}

const fetchEmployee = async (url: string, id: number): Promise<Record<string, string>> => {
    const response = await fetch(`${url}/${id}`)
    const { data } = await response.json()
    return data
}
const generateEmail = (name: string): string => {
    return `${name.split(' ').join('.')}@company.com`
}

const runAsyncFunctions = async () => {
    try {
        const employees = await fetchAllEmployees(baseApi)
        Promise.all(
            employees.map(async user => {
                const userName = await fetchEmployee(userApi, user.id)
                const emails = generateEmail(userName.name)
                return emails
            })
        )
    } catch (error) {
        console.log(error)
    }
}
runAsyncFunctions()

В вышеприведенном коде fetchEmployees выбирает всех сотрудников из  baseApi. Мы ожидаем отклик (await), преобразуем его в JSON, а затем возвращаем преобразованные данные.

Самое важное, о чем здесь нужно помнить – как мы последовательно выполняли код строка за строкой внутри функции async с ключевым словом await. Мы бы получили ошибку, если бы попытались преобразовать в JSON данные, которых дождались не полностью. То же касается fetchEmployee, с той оговоркой, что выбирали бы всего одного сотрудника. Более интересен фрагмент runAsyncFunctions, где все асинхронные функции выполняются конкурентно.

Сначала обернем в блок try/catch все методы, находящиеся внутри runAsyncFunctions. Далее ждем (await) результат выбора всех сотрудников. Нам нужен id каждого сотрудника, чтобы выбрать соответствующие им данные, но в конечном счете нам нужна именно информация о сотрудниках.

Вот где можно прибегнуть к Promise.all, чтобы конкурентно обработать все Promises. Каждый fetchEmployee Promise конкурентно выполняется для всех сотрудников. Информация о сотрудниках, которую мы дождемся, используется для генерации электронного сообщения от каждого сотрудника, это делается при помощи функции generateEmail.

Если случится ошибка, то она распространяется как обычно, от невыполненного обещания к Promise.all, а затем превращается в исключение, которое можно отловить в блоке catch.

Ключевые выводы

async и await позволяет писать асинхронный код так, что он выглядит и действует как синхронный. Такой код становится гораздо проще читать, писать и судить о нем.

Завершу статью несколькими ключевыми тезисами; помните о них, когда будете работать над вашим следующим асинхронным проектом на TypeScript.

  • await работает только внутри функции async 

  • Функция, помеченная ключевым словом async, всегда возвращает Promise

  • Если возвращаемое значение внутри async не возвращает Promise, то оно будет обернуто в немедленно разрешаемый Promise

  • Как только встретится ключевое слово await, выполнение приостанавливается, пока не будет завершено Promise 

  • await либо вернет результат от выполненного Promise, либо выбросит исключение от отклоненного Promise

Комментарии (18)


  1. MaZaAa
    25.10.2021 11:26
    +3

    Режет глаза отсутствие; в конце строк в коде. Не надо свои странные предпочтения выставлять на публику.


    1. haymob
      25.10.2021 12:15
      -1

      Typescript дописывает ; при компиляции в js, если вам не доплачиваю за ; результат будет одинаковый.


    1. mukhindev
      25.10.2021 12:15
      +6

      С каких пор это порицается? Пунктуальная нетерпимость какая-то) На всекий случай предостерегаю вас от захода в некоторые открытые репозитории и документации этих компаний https://standardjs.com/#who-uses-javascript-standard-style


      1. qrKot
        26.10.2021 21:48

        Странно видеть ссылку на JS-стайл в контексте статьи по TS...

        Тем более линтер может нарисовать эти ; за вас, а публиковать в статье код, не видевший линтера, таки моветон.


        1. muturgan
          29.10.2021 15:32
          +1

          Знаю проекты на тс, в которых в стайлгайдах и настройках линтера закреплено отсутствие точек с запятой.

          Приравнивать несоответствие вашим предпочтениям к недостатку, таки моветон.

          ПС. Я люблю ;


    1. Metotron0
      25.10.2021 14:48
      +6

      Разве этот комментарий не является эттм самым выставлением?


  1. Metotron0
    25.10.2021 14:44
    +1

    Вопрос по языку: зачем после Promise написали обобщённый тип <T>, если он больше нигде не упоминается? Я думал, это нужно, чиобы обрзначить, что на выходе или у какого-то параметра такой же тип, как на входе, но здесь ни один параметр не имеет тип T и на выходе его нет.


    1. Xazzzi
      25.10.2021 15:11

      Ошибка же, там дожен был быть unknown или any на худой конец.


      1. Metotron0
        26.10.2021 01:58

        А, это какой-то обёрнутый в скрытую логику тип данных TS, которому нужно передать, что будет после разрешения промиса?


        1. Xazzzi
          26.10.2021 11:05
          +1

          Вы правильно пишете, тип Т неоткуда взять. Вместо Promise<T> для результата можно прописать Promise<unknown> , тогда значение которое выдаст await будет иметь тип unknown и не получится его случайно использовать не проверив на соответствие типу (например через type predicate), в отличии от any.


          1. achidutsu
            27.10.2021 01:46

            А можно просто не использовать TypeScript например и вообще ничего там не писать )

            Смотрите сколько сразу снимается вопросов.


            1. diomas
              27.10.2021 10:13

              так и в тайпскрипте можно явно не писать тип промиса: ide его выведет из типа аргумента, переданного в resolve


  1. faiwer
    25.10.2021 17:24
    +10

    const runAsyncFunctions = async () => {
        try {
            const employees = await fetchAllEmployees(baseApi)
            Promise.all(
                employees.map(async user => {
                    const userName = await fetchEmployee(userApi, user.id)
                    const emails = generateEmail(userName.name)
                    return emails
                })
            )
        } catch (error) {
            console.log(error)
        }
    }

    вы тут await перед Promise.all забыли. Без него всё насмарку.


    upd1. и ещё забыли return, иначе какой смысл писать return emails.
    upd2. и скорее всего нужен .flat() а то у вас странный список email[][] получается :-) переменная названа криво, т.к. email один, должно быть email (без s).


  1. Delagen
    26.10.2021 11:05

    Первый же пример "более менее" не эквивалентен. Первый возвращает свойство data от результата fetch, а второй просто результат.


  1. qrKot
    26.10.2021 21:45
    -1

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

    В переводе с английского «promise» означает «обещание». В JavaScript промис описывает ожидание того, что некоторое событие произойдет в определенный момент, и ваше приложение полагается на результат этого будущего события при выполнении определенных других задач.

    ...

    Заметили паттерн? Первая очевидная вещь, которую нужно отметить – второе событие полностью полагается на первое. Если будет выполнено обещание, заложенное в первом событии, то выполнится и следующее событие. Промис в том событии либо выполняется, либо не выполняется, либо остается в подвешенном состоянии.

    ...

    Мы объявили promise при помощи ключевого слова new + Promise, где промис принимает аргументы resolve и reject. Теперь давайте напишем промис, выражающий события из вышеприведенной блок-схемы.

    ...

    Теперь можно сцепить промисы, что позволяет выполнять их последовательно с применением .then. Эти функции похожи на обычный человеческий язык: сделай так, а затем вот это, а потом то и так далее.

    Шел 16-й (шестнадцатый) абзац пространной статьи об асинхронном программировании в TS, но до сих пор ни разу не было упомянуто, чем все эти городки с Promise'ами отличаются от if/then/else.

    Мы рассказали про порядок выполнения промисов, про то, как их chain'ить, трижды привели косячные примеры кода, определили зависимость выполнения одних промисов от результатов других...

    Бывает так, что необходимо параллельно или последовательно выполнять сразу множество обещаний.

    20-й абзац... уже где-то почти совсем рядом...

    Представьте, к примеру, сто нужно выбрать список из 1 000 пользователей GitHub, а затем сделать дополнительный запрос с ID, чтобы выбрать для каждого из них аватарки. Совсем не обязательно вы захотите дожидаться завершения этих операций со всеми пользователями в последовательности; вам нужны только все выбранные аватарки. Мы подробнее поговорим об этом ниже, когда будем обсуждать Promise.all.

    Нет, блин, опять какую-то фигню написали. Каким боком Promise.all помогает "не обязательно ... дожидаться завершения этих операций со всеми пользователями в последовательности" - решительно непонятно. Он же, вроде, и нужен для того, чтобы всенепременнейше дождаться прямо конкретно всех, без исключения?

    Теперь, когда вы в общем и целом поняли, что такое промисы

    Нет, все еще решительно не понимаю... Так ни разу слов "асинхронное выполнение" и примеров, хотя бы как-то с оными связанных, и не встретил. А так-то 25-й абзац уже...

    Синтаксис Async/await удивительно прост при работе с промисами. Он предоставляет простой интерфейс для чтения и записи промисов, причем, таким образом, что они кажутся синхронными

    Ребят, вы весь текст до этого ни разу не сказали, что промисы - асинхронные! Ну камон, вы чо, блин?

    Даже если пропустить ключевое слово Promise, компилятор обернет вашу функцию в немедленно разрешаемый промис.

    Ну вот может у меня компилятор какой-то не такой, но конкретно мой компилятор ничего ни во что оборачивать не стал. Он просто вывалил мне ошибку и ничего собирать не стал. И я даже с ним согласен, я бы тоже не стал.

    Конструкция async/await всегда возвращает Promise

    Ну нет же, право слово. async-функция всегда возвращает Promise, а await всегда дожидается, пока он зарезолвится. А что такое конструкция async/await - решительно непонятно. Например, можно объявить async функцию, и не await'ить ее. А await вполне себе используется не только в вызовах async-функций, например, можно `await somePromise` делать, это законно. И это именно потому, что никакой конструкции async/await нет, есть async(асинхронные функции), которые всегда обязаны возвращать промисы, и есть ключевое слово await, которое заставляет текущий поток исполнения дождаться, пока уже возвращенный асинхронной функцией промис зарезолвится.

    Таким образом, можно трактовать возвращаемое значение функции async как Promise

    Зачем трактовать-то? Это ж он и есть!

    что довольно полезно, когда нужно разрешать сразу множество асинхронных функций

    Опачки, здравое зерно! Какой по счету абзац? Я что-то сбился.

    Как понятно из названия, async с await всегда ходят парой.

    Блин, вы опять все испортили! Во-первых, вообще не понятно из названия, во-вторых, вообще не обязаны парой ходить... Можно пнуть асинхронную функцию и не дожидаться выполнения - это законно, хоть и не приветствуется (async без await). Можно просто взять готовый промис и дождаться его выполнения, что не только законно, но и в целом очень даже приветствуется (await без async).

    То есть, делать await можно только внутри функции async

    Ну да, await может быть использован только внутри async-функции, это да. Но ваше "то есть" предполагает, что это само собой разумеется из сказанного ранее. А это не так... Вообще никакой связи.

    Тем более что запрет на использование await'а извне асинхронных функций таки стоит сильно сбоку от "async/await, ходящих парой". Если мы уж пару ищем, то, предположительно, имеем в виду связанную между собой пару из вполне конкретного async в сигнатуре функции и конкретного await'а, который резолва конкретно возвращаемого ей промиса ждет. Ну так вот, сейчас будет срыв покровов: тот await, который ждет разрешения асинхронной функции всегда и гарантировано находится снаружи относительно самой функции.

    Вы что, просто из MSDN в произвольном порядке фразы дергаете и гуглотранслейтом их переводите?

    const myAsync = async (): Promise<Record<string, number | string>> => {
        await angelMowersPromise
        const response = await myPaymentPromise
        return response
    }

    Сразу заметно, что этот код выглядит более удобочитаемым и кажется синхронным.

    Да он в контексте описанной функции и является синхронным! Ключевое слово async = асинхронное выполнение, а ключевое слово await - это оператор синронизации состояния.

    Допустим, например, что у нас лег сервер

    Мы должны приостановить выполнение, чтобы предотвратить обвал программы

    Что, простите, мы должны предотвратить? Вы же сами говорите, он УЖЕ лег.

    В качестве возвращаемого значения ожидаем массив типа typeof

    Странный какой-то тип. У меня, почему-то, есть чувство, что тип с именем typeof в TypeScript объявить нельзя...

    Если какое-то исключение ускользнет, то может получиться код, плохо поддающийся отладке, либо даже может быть испорчена вся программа.

    Ну, например, ровно как в вашем примере, выброшенный Exception (который не является наследником Error) вполне "испортит всю программу".

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

    Вот сейчас вообще не очевидно стало. Вы уж определитесь, синхронно (выполнение инструкций последовательно, в порядке описания в коде программы), или таки параллельно (очевидно, в каком-то другом порядке). Да и вообще, откуда вы это "параллельно" взяли. Асинхронно - правильный термин, параллельность TS вообще никак не гарантирует.

    Или про то, чем асинхронность от параллельности отличается, тоже надо рассказать?

    Как пишет Mozilla, “Promise.all обычно применяется после того, как было запущено множество асинхронных задач, которые должны работать конкурентно, и после того, как пообещали, каковы будут их результаты – чтобы можно было дождаться, пока все эти задачи будут завершены.”

    Зачем вы оговариваете Mozilla? Не могли они такую дичь написать! Это просто у вас перевод корявый.

    В псевдокоде было бы что-то подобное:

    • Выбрать всех пользователей => /employee

    • Дождаться всех данных о пользователях. Извлечь id от каждого пользователя. Выбрать каждого пользователя => /employee/{id}

    • Сгенерировать электронное сообщение для каждого пользователя по его имени

    Псевдокод у вас тоже неправильный, последовательный (т.е. синхронный) алгоритм описан. При чем тут Promise.all?

     Мы ожидаем отклик (await), преобразуем его в JSON

    А вы это, простите, зачем делаете? (подсказка: в коде происходит не то, что вы пишете).

    Самое важное, о чем здесь нужно помнить – как мы последовательно выполняли код строка за строкой внутри функции async с ключевым словом await. Мы бы получили ошибку, если бы попытались преобразовать в JSON данные, которых дождались не полностью.

    Божечки, что вы несете? Муля, никогда не доверяй важное дело идиотам!

    Более интересен фрагмент runAsyncFunctions, где все асинхронные функции выполняются конкурентно.

    Вот это верно, он, как раз, и есть то, заради чего вся эта муть писалась. Это прям апогей, апофеоз, самая цели статьи и вишенка на торте...

    Каждый fetchEmployee Promise конкурентно выполняется для всех сотрудников.

    ... которая в тупую и совершенно бездарно слита буквально через абзац. Как и вся статья...

    async и await позволяет писать асинхронный код так, что он выглядит и действует как синхронный

    Просто нет слов... Еще раз повторю: async - ключевое слово, означающее асинхронный запуск, await - инструмент синхронизации. await не позволяет писать асинхронный код, await - напрямую команда синхронного исполнения.

    Честное слово:
    Муля Издательский дом "Питер", не доверяй серьезное дело публикацию статей от своего имени на хабре идиотам рерайтерам.


    1. Saiv46
      03.11.2021 07:39
      +2

      Человек по делу написал, а вы его минусуете.

      Конечно и оригинал такой себе, вот пример:

      // Я отправляю запрос в компанию. Он синхронный
      // Компания обещает мне выполнить работу
      const angelMowersPromise = new Promise<string>((resolve, reject) => {
          // Обещание разрешилось спустя несколько часов
          setTimeout(() => {
              resolve('We finished mowing the lawn')
          }, 100000) // разрешается спустя 100 000 мс
          reject("We couldn't mow the lawn")
      })

      Данный Promise будет отвергнут сразу же, не смотря на то, что спустя 100с он будет разрешён (да и писал это человек что явно не знает как работают промисы).


  1. Julia_Konovalova
    28.10.2021 12:48
    +1

    Спасибо! Было полезно прочитать ещё раз другими словами и с понятными примерами, хоть мне пока не нужен Typescript, я изучаю JS

    В части Promise.All было уже не так легко понять, но всё равно спасибо ????


  1. muturgan
    29.10.2021 15:27

    Довольно подробное руководство по промисам и async/await. Но при чем тут тайпскрипт?