Цель этого руководства — показать вам, как вы можете использовать функцию async/await в новейшей версии Javascript. Я быстро и безболезненно объясню, как можно заменить промисы на async/await, правильно обработаю ошибки и рассмотрю простые синхронные и параллельные методы асинхронного ожидания.
Обязательно используйте последнюю версию nodejs (версия ›7.6.0), поскольку она поддерживает асинхронность/ожидание из коробки, но если вы не можете использовать последнюю версию node, вы можете использовать BabelJS для преобразования вашего кода в эквивалент ES6.
Для начала мы будем использовать две функции на основе промисов в качестве примеров асинхронных вызовов:
function getPentaCodeAvatar() { return new Promise((resolve, reject) => { github.search.users({ q: 'pentacode' }, (err, res) => { if (err) { reject(err); return; } let avatarUrl = ''; if (res.data && res.data.items) { avatarUrl = res.data.items[0].avatar_url; } resolve(avatarUrl); }); }) }
function getReactAvatar() { return new Promise((resolve, reject) => { github.search.users({ q: 'react' }, (err, res) => { if (err) { reject(err); return; } let avatarUrl = ''; if (res.data && res.data.items) { avatarUrl = res.data.items[0].avatar_url; } resolve(avatarUrl); }); }) }
Это очень простые функции, основанные на обещаниях, которые используют пакет Github NPM для получения аватара пользователя с сервера Github.
Замените промисы на асинхронное ожидание
Чтобы вызвать вышеупомянутые функции с промисами, мы должны сделать:
getPentaCodeAvatar()
.then((result) => {
console.log(result);
})
.catch((e) => {
console.error('Error in getPentaCodeAvatarFunction (Promise Based)', e);
});
Синтаксис чистый и простой, определенно лучше, чем вложенные обратные вызовы. Ошибка обнаружена в функции .catch(). Что меня беспокоит, так это многочисленные анонимные функции, передаваемые в .then() и .catch(), которые все еще не так чисты, как хотелось бы.
Давайте посмотрим, как мы можем сделать это с помощью async/await:
async function start() { const avatarUrl = await getPentaCodeAvatar(); console.log(avatarUrl); }
start();
Что это за магия? Вы говорите, что этот код выглядит синхронно, ну, это и есть цель, мы сначала обработаем слово function ключевым словом async, это сообщит компилятору, что следующая функция использует асинхронные вызовы чего-то, затем мы добавьте ключевое слово await перед функцией обещания getPentaCodeAvatar(), это заставит функцию ждать, пока асинхронный код внутри getPentaCodeAvatar() не выполнит закончите перед установкой результата в переменную avatarUrl. Имейте в виду, что вы можете использовать ключевое слово await только внутри функции с пометкой async, иначе вы получите синтаксическую ошибку от node.
Обработка ошибок
С промисами вы можете перехватывать ошибки с помощью функции .catch(), но как это сделать с помощью Async/Await? Ответ: try…catch, вы просто заключаете код в try…catch, и ошибки будут обнаружены:
async function start() { try { const avatarUrl = await getPentaCodeAvatar(); console.log(avatarUrl); } catch (e) { console.error('Error in getPentaCodeAvatarFunction (Async Await Based)', e); } }
start();
Хорошая вещь в этом заключается в том, что вы сможете отлавливать ошибки внутри функции обещания И что-либо внутри блока try, например ошибку JSON.parse. IMO, это намного мощнее и знакомо среднему разработчику, недостатком этого является то, что вам придется писать много попыток/уловов.
Синхронный
Допустим, вам нужно вызвать две или три асинхронные функции и вам нужны результаты предыдущих вызовов, чтобы выполнить следующую, другими словами, синхронные вызовы, тогда следующий пример покажет вам, как это сделать:
async function startSynchronous() { try { const pentaCodeAvatarUrl = await getPentaCodeAvatar(); const reactAvatarUrl = await getReactAvatar(); const totalURL = pentaCodeAvatarUrl + reactAvatarUrl; console.log(totalURL); } catch (e) { console.error('Error in startSynchronous (Async Await Based)', e); } }
startSynchronous();
Это очень похоже на обычные вызовы и присваивания функций: вы вызываете getPentaCodeAvatar() и получаете значение результата, сохраненное в переменной, затем вызываете getReactAvatar() и сохраняете результат. в том, что в другой переменной, и, наконец, вы объединяете их вместе в другой переменной. async/await упрощает понимание и позволяет безболезненно манипулировать переменными из различных асинхронных функций.
Параллельно
А если вы хотите, чтобы набор асинхронных функций выполнялся одновременно и параллельно?
async function startParallel() { try { let [ pentaCodeAvatarUrl, reactAvatarUrl ] = await Promise.all([getPentaCodeAvatar(), getReactAvatar()]); console.log(pentaCodeAvatarUrl, reactAvatarUrl) } catch (e) { console.error('Error in startParallel (Async Await Based)', e); } }
startParallel();
Правильно, вы можете обернуть их в Promise.all и использовать перед ним ключевое слово await. Это МОЩНО, потому что оно сочетает в себе возможности async/await и промисов для выполнения того, что мы хотим, и в процессе делает код очень простым для понимания.
Я надеюсь, что эти четыре примера объяснили силу async/await, и я надеюсь, что вы сможете начать включать их в свои проекты.
Эта история была перепечатана на Medium. Оригинал истории можно найти на https://www.penta-code.com/blazing-fast-static-reactjs-site-with-gatsby-js