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

Async и await

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

Асинхронные функции — это такие, которые объявлены с использованием ключевого слова 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 {
    // выполнится в любом случае, в независимости от того произошла ошибка или нет
  }
}

Пример кода

Пример, в котором напишем асинхронный код для получения данных с сервера JSONPlaceholder:

// асинхронная функция для получения данных пользователя в формате JSON
const getUser = async(id) => {
  try {
    const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
    if (!response.ok) {
      throw new Error('Ответ сервера не в диапазоне 200-299');
    }
    const data = await response.json();
    return data;
  } catch (e) {
    throw new Error('Ошибка при получении данных пользователя');
  }
}
// функция для отображения данных пользователя на странице
const renderUsers = (users) => { ... }
// асинхронная функция, в которой сначала вызывается getUser(), а затем renderUsers() для отображения полученных на странице
const clickUser = async(id) => {
  try {
    const data = await getUser(id);
    const users = Array.isArray(data) ? data : [data];
    renderUsers(users);
  } catch (e) {
    console.error(e);
  }
}
Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!
Эйч Маркетинг