Полный цикл в digital

Async и await

Внедение стандарта ES2017 в JavaScript привнесло два новых оператора: async и await, который призваны упростить работу с классическими промисами.

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

  1. Оборачивает возвращаемое значение в Promise
  2. Позволяет использовать ключевое слово await

Принцип работы

Оператор async определяет асинхронную функцию, в которой будет выполняться одна или несколько асинхронных задач:

async function название_функции(){
    // асинхронные операции
}

Внутри асинхронной функции мы можем применить оператор await. Он ставится перед вызовом асинхронной операции, которая представляет объект Promise:

async function название_функции(){
    await асинхронная_операция();
}

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

Async

Асинхронные функции — это такие функции, которые объявлены с использованием ключевого слова async, оператор async определяет асинхронную функцию, в которой будет выполняться одна или несколько асинхронных задач:

// асинхронная функция delay
async function delay() {
  // ...
}
// асинхронная функция как часть выражения
const wait = async function() {
  // ...
}
// стрелочная запись асинхронной функции sleep
const sleep = async() => {
  // ...
}

В качестве результата асинхронная функция всегда возвращает промис. Если в качестве значения вернуть не промис, то она автоматически обернёт его в успешно завершившийся промис:

const hello = async() => {
  return 'Hello!';
}
const result = hello();
console.log(result); // [object Promise] { ... }

Результат будет одинаковым, если вместо 'Hello!' вернуть Promise.resolve('Hello!'):

const hello = async() => {
  return Promise.resolve('Hello!');
}

Так как возвращаемое значение является промисом, то мы можем его обработать с помощью метода then():

const hello = async() => {
  return 'Hello!';
}
const result = hello();
// "Hello!"
result.then(value => console.log(value));

Или упрошенный вариант:

const hello = async() => {
  return 'Hello!';
}
// "Hello!"
hello().then(value => console.log(value));

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

const someFunc = async() => {
  throw new Error('Oops');
}
// Error: Oops
someFunc().catch(error => console.error(error));

Внутри асинхронных функций перед промисами можно указывать await.

Await

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

// функция, возвращающая промис
function delay(ms, str) {
  return new Promise (resolve => setTimeout(() => {
    resolve(str);
  }, ms));
}
// асинхронная функция
async function message() {
  // ждём выполнение первого промиса delay(1000, 'Игорь') и сохраняем его результат в переменную a
  let a = await delay(1000, 'Игорь');
  // после завершения первого промиса, переходим к выполнению второго delay(2000, 'Егор')
  let b = await delay(2000, 'Егор'); // как только он завершится помещаем его результат в переменную b
  // после завершения второго промиса, переходим к выполнению третьего delay(4000, 'Денис')
  let c = await delay(4000, 'Денис'); // как только он выполнится сохраняем его результат в переменную c
  // выводим значения переменных в консоль
  console.log(`${a} ${b} ${c}`); // "Игорь Егор Денис"
}
// вызываем асинхронную функцию
message();

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

Обработка ошибок

Обработать потенциальные ошибки в асинхронной функции можно с помощью try..catch. Для этого этот блок кода (в котором используется await) необходимо заключить в эту конструкцию:

async function getUser() {
  try {
    const response = await fetch(url);
    const data = await response.json();
  } catch(e) {
    // если что-то пойдёт не так на каком-то этапе в блоке try, то мы автоматически попадём в метод catch()
    console.error(e);
  }
}

Если нужно с finally, то так:

async function getUser() {
  try {
    const response = await fetch(url);
    const data = await response.json();
  } catch(e) {
    // если что-то пойдёт не так на каком-то этапе в блоке try, то мы автоматически попадём в метод catch()
    console.error(e);
  } finally {
    // выполнится в любом случае, в независимости от того произошла ошибка или нет
  }
}

Пример кода

Для примера переделаем наш код с использованием async/await:

function math() {
    return new Promise((resolve, reject) => {
        // оценку, которые мы получим определим случайным образом спустя некоторое время (например, 5 секунд)
        setTimeout(() => {
            // сгенерируем оценку от 2 до 5
            const mark = Math.floor(Math.random() * 4) + 2;
            // если оценка больше 3, то...
            if (mark > 3) {
                // завершим промис успешно, для этого вызовем функцию resolve() и передадим в функцию оценку
                resolve(`Ура! Я сдал экзамен на ${mark}! Папа, как и обещал дал мне 100$.`);
            } else {
                // завершим промис с ошибкой, для этого вызовем функцию reject() и передадим в функцию оценку
                reject(`Увы, я получил оценку ${mark}! Папа мне не дал 100$`);
            }
        }, 5000);
    });
}
async function message() {
    try {
    // успешное выполнение 
    console.log(await math());
    } catch(e) {
        // если что-то пойдёт не так в блоке try, мы автоматически попадём в метод catch()
        console.error(e);
    }
}
// вызываем асинхронную функцию
message()
Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!
Эйч Маркетинг