1. Напишите асинхронную функцию с помощью async / await

Здесь у нас есть короткая функция, которая общается с API github.

const fetch = require(‘node-fetch’)
function showGithubUser(handle) {
  const url = `https://api.github.com/users/${handle}`
  fetch(url)
    .then(resp => resp.json())
    .then(user => {
      console.log(user.name)
      console.log(user.location)
    })
}
showGithubUser(‘minsooshin’)

Он загружает конкретного пользователя и после получения ответа анализирует тело как JSON. Наконец, имя и местоположение пользователя заносятся в консоль.

Давайте посмотрим, как мы можем преобразовать эту функцию в асинхронную с помощью ключевых слов async и await.

1. Сделайте функцию асинхронной, добавив ключевое слово async.
2. Используя оператор await, чтобы дождаться завершения вызова выборки.
* Оператор await принимает обещание и приостанавливает выполнение функции до тех пор, пока обещание не будет выполнено.
3. Назначьте значение, возвращаемое оператором await, переменной.
4. Возьмите текст ответа и проанализируйте его как JSON.
5. Распечатайте результат.

const fetch = require(‘node-fetch’)
async function showGithubUser(handle) {
  const url = `https://api.github.com/users/${handle}`
  const resp = await fetch(url)
  const user = await resp.json()
  console.log(user.name)
  console.log(user.location)
}
showGithubUser(‘minsooshin’)

Чтобы использовать этот async / await, используйте узел 7.6 или более поздней версии.

2. Вызов асинхронной функции в цепочке обещаний.

Теперь функция showGithubUser выбирает пользователя из Github API, а затем выводит имя и местоположение на консоль. Давайте отремонтируем эту программу так, чтобы функция извлекала только пользователя и возвращалась вызывающей стороне, которая могла решить, что с ней делать.

1. Избавьтесь от строк console.log и просто верните пользователя; вызывается showGithubUser, он возвращает обещание.
2. Мы можем построить цепочку обещаний с помощью метода .then.

const fetch = require(‘node-fetch’)
async function fetchGithubUser(handle) {
  const url = `https://api.github.com/users/${handle}`
  const resp = await fetch(url)
  return await resp.json()
}
fetchGithubUser(‘minsooshin’)
  .then(user => {
    console.log(user.name)
    console.log(user.location)
  })

Этот пример показывает, что довольно легко вызвать асинхронную функцию как часть цепочки обещаний. Каждая функция async возвращает обещание, поэтому вы можете просто вызвать .then и .catch возвращаемого значения.

3. Преобразование любой функции в асинхронную функцию

JavaScript позволяет нам преобразовать любую функцию в асинхронную функцию. До сих пор мы работали с объявлением функции, но еще не рассмотрели функциональные выражения, стрелочные функции или методы. Давайте преобразуем это объявление функции в выражение функции.

1. Вырежьте имя fetchGithubUser и введите переменную, а затем назначьте выражение функции.

const fetch = require(‘node-fetch’)
// function expression
const fetchGithubUser = async function (handle) {
  const url = `https://api.github.com/users/${handle}`
  const resp = await fetch(url)
  return await resp.json()
}
// arrow function
// const showGithubUser = async function (handle) => {
fetchGithubUser(‘minsooshin’)
  .then(user => {
    console.log(user.name)
    console.log(user.location)
  })

Давайте посмотрим на хороший пример использования выражения асинхронной функции. Ключевое слово await может использоваться только в асинхронных функциях, поэтому мы не можем использовать его на верхнем уровне файла.

// this code doesn’t work
const user = await fetchGithubUser(‘minsooshin’)
console.log(user.name)
console.log(user.location)
// to fix, wrap with `async`
(async function() {
  const user = await fetchGithubUser(‘minsooshin’)
  console.log(user.name)
  console.log(user.location)
})()

Наконец, давайте реализуем асинхронный метод класса.

1. определите класс с именем GithubApiClient.
2. определите метод для получения пользовательских данных.
3. поместите ключевое слово async перед метод.
4. создать экземпляр класса
5. вызвать метод с использованием экземпляра

const fetch = require(‘node-fetch’)
class GithubApiClient {
  async fetchUser (handle) {
    const url = `https://api.github.com/users/${handle}`
    const resp = await fetch(url)
    return await resp.json()
  }
}
(async function () {
  const client = new GithubApiClient()
  const user = await client.fetchUser(‘minsooshin’)
  console.log(user.name)
  console.log(user.location)
})()

4. Обработка ошибок в асинхронных функциях

Давайте воспользуемся примером из раздела 2. Что произойдет, если мы попытаемся загрузить пользователя, которого на самом деле не существует? Если вы запустите программу, вы получите это.

Посмотрим, как выглядит объект ответа. Мы выйдем из системы для пользователя, а не для отдельного свойства.

Наша функция fetchGithubUser всегда возвращает обещание, которое разрешает это значение. Это не то, что мы хотим. Вместо этого мы хотим отклонить это обещание с сообщением об ошибке.

1. Сохраните возвращаемое значение JSON в переменной
2. Если статус ответа не успешен, выдайте ошибку
3. Добавьте метод catch в наше обещание. цепь

const fetch = require(‘node-fetch’)
async function fetchGithubUser(handle) {
  const url = `https://api.github.com/users/${handle}`
  const resp = await fetch(url)
  const body = await resp.json()
  if (resp.status !== 200) {
    throw Error(body.message)
  }
  return body
}
fetchGithubUser(‘minsooshin’)
  .then(user => {
    console.log(user.name)
    console.log(user.location)
  })
  .catch(err => {
    console.log(`Error: ${err.message}`)
  })

Этот подход работает, потому что асинхронная функция автоматически возвращает отклоненное обещание всякий раз, когда возникает ошибка. Это то, что мы можем просто написать метод catch, а затем обработать отклоненное обещание.
Еще одно преимущество ключевых слов async / await заключается в том, что мы можем использовать обычный оператор try / catch. Это невозможно для простых обещаний, потому что функция обратного вызова всегда вызывается асинхронно.

Чтобы проиллюстрировать, как async / await сочетается с блоками try / catch,
1. convert prom цепочку в асинхронную функцию
2. Добавьте обычный оператор try / catch

const fetch = require(‘node-fetch’)
async function fetchGithubUser (handle) {
  const url = `https://api.github.com/users/${handle}`
  const resp = await fetch(url)
  const body = await resp.json()
  if (resp.status !== 200) {
    throw Error(body.message)
  }
  return body
}
async function showGithubUser (handle) {
  try {
    const user = fetchGithubUser(handle)
    console.log(user.name)
    console.log(user.location)
  } catch (err) {
    console.log(`Error: ${err.message}`)
  }
}

Исходный код и полное руководство: https://egghead.io/lessons/javascript-write-an-asynchronous-function-with-async-await