Что такое обещание JavaScript? Это когда код клянется работать каждый раз.

Давайте создадим кнопку, которая будет:

  • выполнить дорогостоящую синхронную операцию,
  • запустить 2 запроса AJAX и
  • обновить DOM на основе ответов AJAX.

Вот разметка.

Вот функции. Давайте также измерим продолжительность каждой операции с помощью Performance API, который визуализирует, когда и как долго каждая функция выполняется на временной шкале производительности Chrome DevTools. (Спасибо JSONPlaceholder за фиктивные конечные точки.)

Вы по-прежнему здесь? Хорошо, вот и самое интересное: написание обработчика onclick для button. Поскольку все крутые ребята этим занимаются, давайте воспользуемся async / await.

async function handleClick() {
   someSyncOperation(); // Expensive sync operation 
   const postJson = await fetchPost(); // AJAX request #1
   const commentsJson = await fetchComments(); // AJAX request #2
   appendPostDOM(postJson);
   appendCommentsDOM(commentsJson);
}

Вот график производительности после нажатия кнопки button.

Давайте посмотрим поближе.

Имеет смысл, существует множество статей о том, как async / await превращает асинхронный код в код блокировки. К вашему сведению, каждая полоса составляет около 2 секунд при настройке сети на «Медленный 3G».

Таким образом, общее время выполнения составляет 6 секунд.

OK. fetchPost и fetchComments могут выполняться параллельно, поэтому давайте воспользуемся комбинацией await Promise.all.

async function handleClick() {
  someSyncOperation();
  const [ postJson, commentsJson ] = await Promise.all([
    fetchPost(), 
    fetchComments()
  ]);
  appendPostDOM(postJson);
  appendCommentsDOM(commentsJson);
}

Общее время выполнения теперь составляет 4 секунды с тех пор, как fetchPost и fetchComments выполняются параллельно.

OK. Поскольку someSyncOperation не зависит от запросов AJAX, давайте посмотрим, ускорит ли перемещение его в последнюю строку функции.

async function handleClick() {
  const [ postJson, commentsJson ] = await Promise.all([
    fetchPost(), 
    fetchComments()
  ]);
  appendPostDOM(postJson);
  appendCommentsDOM(commentsJson);
  someSyncOperation();
}

Нет, общее время выполнения по-прежнему составляет 4 секунды.

OK. Пора переходить к «полному обещанию».

function handleClick() {
  Promise.all([
    fetchPost(),
    fetchComments()
  ]).then(([ postJson, commentsJson ]) => {
    appendPostDOM(postJson);
    appendCommentsDOM(commentsJson)
  });
  someSyncOperation();
}

Переход на «полное обещание» сокращает общее время выполнения до 2 секунд.

Причина, по которой это работает, заслуживает отдельной статьи, но вот отличное объяснение.

Сегодня я узнал.

Бонус

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

async function handleClick() {
  const postPromise = fetchPost();
  const commentsPromise = fetchComments();
  
  someSyncOperation();
  const postJson = await postPromise;
  const commentsJson = await commentsPromise;
  appendPostDOM(postJson);
  appendCommentsDOM(commentsJson);
}

Понравилась эта статья? Если да, то получите больше похожего контента, подписавшись на наш канал на YouTube в Decoded!

📫 Напишите мне в LinkedIn или по электронной почте!