Готовый перевод Modern JS Cheatsheet / Памятка по современному JavaScript: Async Await
### Async Await
Помимо [Промисов](#promises), вам может встретиться еще один синтаксис для обработки асинхронного кода - *async / await*.
Цель функций async/await - упрощение поведения при синхронном использовании промисов и выполнение какой-либо обработки группы промисов. Промисы похожи на структурированные обратные вызовы, а async/await точно так же похожи на комбинацию генераторов и промисов. ([См: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function))
> **Примечание:** перед тем, как пытаться понять async / await, вы должны понимать, что такое промисы, и как они работают, поскольку async / await основаны на промисах.
> **Примечание 2:** [*await* должен использоваться в *async* функции](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9#f3f0), что означает, что вы не можете использовать await в верхнем уровне вашего кода, т.к. он не находится внутри async-функции.
#### Пример кода
```js
async function getGithubUser(username) { // ключевое слово async позволяет использование await в функции и означает, что функция возвращает promise
try { // Вот так обрабатываются ошибки с помощью async / await
const response = await fetch(`https://api.github.com/users/${username}`); // "синхронное" ожидание promise перед переходом на новую строку
return response.json();
} catch (err) {
alert(err);
}
}
getGithubUser('mbeaudru').then(user => console.log(user)); // логирование пользователя - не может использовать синтаксис await, т.к. этот код не находится внутри async-функции
```
#### Объяснение с помощью примера кода
*Async / Await* построены на промисах, но они позволяют использовать более императивный стиль кода.
Оператор *async* превращает функцию в *промис*, в котором можно использовать оператор *await*.
```js
async function myFunc() {
// можно использовать оператор await, т.к. это async-функция
try {
return "Привет, мир!";
} catch(e) {
throw new Error();
}
}
myFunc().then(msg => console.log(msg)) // "Привет, мир!" -- myFunc превращается в промис из-за оператора async
```
Когда достигается оператор *return* async-функции, промис выполняется с возвращаемым значением. Если внутри async-функции выпадает ошибка, состояние промиса изменится на *rejected*.
Оператор *await* используется для ожидания выполнения *Промиса* и может быть использован только в теле *async*-функции. При этом выполнение кода приостанавливается, пока не будет выполнен промис.
> **Примечание :** *fetch* -- это Промис, который позволяет выполнить AJAX-запрос.
Давайте сначала посмотрим, как мы можем получить пользователя github с помощью промисов:
```js
function getGithubUser(username) {
return new Promise((resolve, reject) => {
fetch(`https://api.github.com/users/${username}`)
.then(response => {
const user = response.json();
resolve(user);
})
.catch(err => reject(err));
})
}
getGithubUser('mbeaudru')
.then(user => console.log(user))
.catch(err => console.log(err));
```
Вот эквивалент с использованием *async / await*:
```js
async function getGithubUser(username) { // превращение в промис + разрешено использование ключевого слова await
try { // Мы обрабатываем ошибки в асинхронной функции с помощью try / catch
const response = await fetch(`https://api.github.com/users/${username}`); // Выполнение останавливается здесь, пока не закончится выполнение promise.
const user = response.json();
return user; // эквивалент разрешения promise getGithubUser со значением user.
} catch (err) {
throw new Error(err); // эквивалент отклонения promise getGithubUser со значением err.
}
}
getGithubUser('mbeaudru')
.then(user => console.log(user))
.catch(err => console.log(err));
```
Синтаксис *async / await* особенно удобен, когда вам нужно связывать взаимозависимые промисы.
Например, вам нужно получить token для того чтобы получить публикацию в блоге в базе данных, а затем информацию об авторе:
```js
async function fetchPostById(postId) {
try {
const token = await fetch('token_url');
const post = await fetch(`/posts/${postId}?token=${token}`);
const author = await fetch(`/users/${post.authorId}`);
post.author = author;
return post;
} catch(e) {
throw new Error(e);
}
}
fetchPostById('gzIrzeo64')
.then(post => console.log(post))
.catch(err => console.log(err));
```
> **Примечание :** Как вы видите, *try / catch* нужны для обработки ошибок. Но если вы используете *роутинг в express*, вы можете использовать middleware, чтобы избежать необходимости обработки ошибок и иметь приятный для чтения код. Смотрите [эту статью Alex Bazhenov](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) для получения дополнительной информации.
#### Дополнительные материалы
- [Async/Await - JavaScript.Info](https://javascript.info/async-await)
- [ES7 Async/Await](http://rossboucher.com/await/#/)
- [6 причин, почему Async/Await в JavaScript заменит Промисы](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9)
- [awaits в JavaScript](https://dev.to/kayis/javascript-awaits)
- [Использование Async Await в Express с Node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016)
- [Функция Async](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)
- [Await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await)
Переведено на Нотабеноиде
http://notabenoid.org/book/70916/381890
Переводчики: a_popova, wizjer, Tomatoknight
Настройки
Готово:
