Начиная с ES7 у нас появилась новая функция для работы с промисами — Async Await. В предыдущих версиях для асинхронного кода использовались только обратные вызовы и промисы. Теперь давайте взглянем на Async Await.

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

обещание – это объект javascript, который содержит другой объект, или, другими словами, обещание – это объект, который может возвращать значение в будущем: либо разрешенное значение, либо причину, по которой оно не разрешено. (например, сетевая ошибка). Подробнее о промисах вы можете узнать здесь.

Давайте посмотрим на пример промисов:

function getFirstSpecialUsers() {
    return fetchSpecialUsers().then(users => {
        console.log(users[0].name);
    });
}

Очень просто, так как же мне поймать ошибки из промиса?

function getFirstSpecialUsers() {
    return fetchSpecialUsers().then(users => {
        console.log(users[0].name);
    }).catch(err => {
        // do something with err ...
    });
}

Метод fetchSpecialUsers возвращает обещание. В ES2016 или ES7 мы можем использовать await. Он действует точно так же, как вызов then() для промиса, но без обратного вызова. Давайте перепишем приведенную выше функцию, используя await:

async function getFirstSpecialUsers() {
    let users = await fetchSpecialUsers();
    console.log(users[0].name);
}

А теперь с обработчиком ошибок:

async function getFirstSpecialUsers() {
    try {
        let users = await fetchSpecialUsers();
        console.log(users[0].name);
    } catch (err) {
        // do something with err ...
    }
}

Отлично, использование async/await позволило нам, наконец, обрабатывать как синхронные, так и асинхронные ошибки с помощью одной и той же конструкции try/catch.

Хорошо, каждый раз, когда вы вызываете функцию getFirstSpecialUsers, вы будете видеть в консоли имя первого пользователя. Но если вы хотите, чтобы функция что-то возвращала? В этом случае у нас есть проблема, давайте посмотрим (я собираюсь использовать NodeJs):

Что здесь происходит?

строка 4: сделать запрос, который возвращает обещание.
строка 5: Эта строка будет выполнена только при выполнении обещания
строка 6: Немедленно вернуть собаку, но на данном этапе это просто обещание
строка 10 : Поскольку возврат является обещанием, у нас нет доступа к реальному объекту, пока обещание не будет разрешено.

Решение — всегда вызывать асинхронную функцию с помощью await, потому что асинхронные функции не ждут сами себя. Итак, правильный способ вызвать эту функцию:

let dog = await getRandonDog();

Но у нас все еще есть беспокойство здесь. Мы не можем использовать await вне асинхронного блока, поэтому вы можете обернуть его внутри другой асинхронной функции следующим образом:

async function invokeRandonDogFunction() {
   let dog = await getRandonDog();
   console.log(dog);
}
invokeRandonDogFunction();

Или используйте традиционный способ:

getRandonDog()
   .then(dog => console.log(dog))

Прежде чем закончить, давайте обратимся к другому примеру, начинающемуся с промисов:

function double(x) {
   return new Promise(resolve => {
      setTimeout(() => {
         resolve(x * 2);
      }, 2000);
   });
}
console.log(double(5)); // output Promise { <pending> }
double(5).then(x => console.log(x)); // output 10

Ожидаемые результаты, не так ли? но если вы хотите в сумме два результата?

// ...
console.log(double(5) + double(10)); // output [object Promise][object Promise]
double(5).then(x => double(5).then(y => console.log(x + y))); // output 30

Хорошо, теперь давайте очистим наш код и сделаем это, используя асинхронное ожидание:

function double(x) {
   return new Promise(resolve => {
      setTimeout(() => {
         resolve(x * 2);
      }, 2000);
   });
}
async function addAsync() {
   let x = await double(5);
   let y = await double(10);
   
   return x + y;
}
addAsync()
   .then(sum => console.log(sum)); // output 30

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

Спасибо!