29
Май
2019

Введение в async и await JavaScript

Введение в async и await JavaScript

От автора: асинхронный JavaScript никогда не был простым. Некоторое время мы использовали обратные вызовы. Затем мы использовали promise. И теперь у нас есть асинхронные функции async и await JavaScript.

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

Асинхронные функции

Асинхронные функции содержат ключевое слово async. Вы можете использовать его в обычном объявлении функции:

async function functionName (arguments) {
 // Делаем что-то асинхронно
}

Вы также можете использовать его в функции стрелки.

const functionName = async (arguments) => { 
// Делаем что-то асинхронно
}

Асинхронные функции всегда возвращают promise

Неважно, что вы возвращаете. Возвращаемое значение всегда будет promise.

const getOne = async _ => { 
return 1 
}
const promise = getOne()
console.log(promise) // Promise

Примечание. Прежде чем двигаться дальше, вы должны изучить, что такое promise JavaScript и как их использовать. В противном случае, вы быстро запутаетесь.

Ключевое слово await

Когда вы вызываете promise, вы обрабатываете следующий шаг в вызове then, например так:

const getOne = async _ => { 
return 1 
}
getOne () 
.then (value => { 
console.log (value) // 1 
})

Ключевое слово await позволяет ожидать разрешения promise. Как только promise разрешен, он возвращает параметр, переданный в вызов then.

const test = async _ => {
 const one = await getOne()
 console.log(one) // 1
}
test()

Возврат await

До возврата promise в await необходимости нет. Вы можете вернуть promise напрямую. (Если вы return await что-то, вы сначала разрешаете исходный promise. Затем вы создаете новый promise из разрешенного значения. Фактически return await ничего не делает. Нет необходимости в дополнительном шаге).

// Нет необходимости делать это 
const test = async _ => {
 return await getOne()
}
test()
 .then(value => {
 console.log(value) // 1
 })

// Вместо этого делаем 
const test = async _ => {
 return getOne()
}
test()
 .then(value => {
 console.log(value) // 1
 })

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

// Вместо этого делаем
const test = _ => {
 return getOne()
}
test()
 .then(value => {
 console.log(value) // 1
 })

Обработка ошибок

Если promise приводит к ошибке, вы обрабатываете ее с помощью вызова catch, например так:

const getOne = async (success = true) => { 
if (success) return 1 
throw new Error ('Failure!') 
}
getOne (false) 
.catch (error => console.log (error)) // Ошибка!

Если вы хотите обработать ошибку в асинхронной функции, вам нужно использовать вызов try/catch.

const test = async _ => {
 try {
   const one = await getOne(false)
 } catch (error) {
   console.log(error) // Failure!
 }
}
test()

Если у вас есть несколько ключевых слов await, обработка ошибок может стать сложной…

const test = async _ => { 
   try { 
     const one = await getOne (false) 
   } catch (error) { 
     console.log (error) // Ошибка! 
   }
  try { 
    const two = await getTwo (false) 
  } catch (error) { 
    console.log (error) // Ошибка! 
  }
  try { 
    const three = await getThree (false) 
  } catch (error) { 
    console.log (error) // Ошибка! 
  } 
}
test()

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

const test = async _ => {
 const one = await getOne(false)
 const two = await getTwo(false)
 const three = await getThree(false)
}
test()
 .catch(error => console.log(error)))

Примечание. Метод Promise catch позволяет перехватывать только одну ошибку.

Несколько await

await блокирует выполнение следующей строки кода JavaScript до разрешения promise. Это может привести к непреднамеренным последствиям замедления выполнения кода.

Чтобы показать это на примере, нам нужно создать задержку перед выполнением promise. Мы можем создать задержку с помощью функции sleep.

const sleep = ms => {
 return new Promise(resolve => setTimeout(resolve, ms))
}

ms — это количество миллисекунд ожидания до разрешения. Если вы передаете в sleep 1000, JavaScript будет ждать в течение одной секунды, прежде чем разрешит promise.

// Используем Sleep
console.log(‘Now’)
sleep(1000)
 .then(v => { console.log(‘After one second’) })

Логи консоли ‘Now’ немедленно. ‘After one second’ — через 1 секунду

Допустим, getOne требуется для разрешения одна секунда. Чтобы создать эту задержку, мы передаем в sleep 1000 (одну секунду). По истечении одной секунды и после разрешения promise мы возвращаем значение 1.

const getOne = _ => {
 return sleep(1000).then(v => 1)
}

Если вы await getOne(), вы увидите, что это займет одну секунду, прежде чем getOne будет разрешена.

const test = async _ => {
 console.log(‘Now’)
 const one = await getOne()
 console.log(one)
}
test()

Логи консоли ‘Now’ немедленно. ‘After one second’ — через 1 секунду

Допустим, вам нужно дождаться трех promise. Каждый promise имеет задержку в одну секунду.

const getOne = _ => {
 return sleep(1000).then(v => 1)
}
const getTwo = _ => {
 return sleep(1000).then(v => 2)
}
const getThree = _ => {
 return sleep(1000).then(v => 3)
}

Если вы выполняете await этих трех promise подряд, вам придется подождать три секунды, прежде чем все три promise будут выполнены. Это нехорошо, потому что мы заставили JavaScript подождать две лишние секунды, прежде чем делать то, что нам нужно.

const test = async _ => {
 const one = await getOne()
 console.log(one)
 const two = await getTwo()
 console.log(two)
 const three = await getThree()
 console.log(three)
 console.log(‘Done’)
}
test()

Консоль показывает «Now» немедленно. Через одну секунду показывается 1. Еще через секунду — 2. Еще через секунду — 3 и «Done» одновременно

Если getOne, getTwo и getThree могут быть выбраны одновременно, вы сэкономите две секунды. Вы можете получить эти три promise одновременно с помощью Promise.all. Для этого:

Создайте три promise

Добавьте все три promise в массив

await массив promise с помощью Promise.all

Вот как это выглядит:

const test = async _ => {
 const promises = [getOne(), getTwo(), getThree()]
 console.log(‘Now’)
 const [one, two, three] = await Promise.all(promises)
 console.log(one)
 console.log(two)
 console.log(three)
 console.log(‘Done’)
}
test()

Консоль показывает «Now» немедленно. Через одну секунду консоль показывает 1, 2, 3 и «Done»

Это все, что вам нужно знать об асинхронных функциях! Я надеюсь, что эта статья была вам полезна.

Автор: Zell Liew

Источник: https://medium.com

Редакция: Команда webformyself.

Share

Тебе может это понравится...