Что такое обещание 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 или по электронной почте!