Готовый перевод 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

Настройки

Готово:

100.00% КП = 1.3