Начиная с 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. Это действительно обеспечивает интуитивно понятную замену работе с промисами.
Спасибо!