Асинхронный JavaScript и ожидание | Кодементор

Асинхронный JavaScript никогда не был простым. Какое-то время мы использовали обратные вызовы. Затем мы использовали обещания. И теперь у нас есть асинхронные функции.

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

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

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

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

async function functionName (arguments) {
  // Do something asynchronous
}

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

const functionName = async (arguments) => {
  // Do something asynchronous
}

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

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

const getOne = async _ => { 
  return 1 
} 

const promise = getOne()
console.log(promise) // Promise

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

Ключевое слово ожидания

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

const getOne = async _ => { 
  return 1 
} 

getOne()
  .then(value => {
    console.log(value) // 1
  })

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

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

test()

Возврата жду

Нет необходимости await прежде чем вернуть обещание. Вы можете вернуть обещание напрямую.

(Если ты return await что-то, вы сначала разрешаете исходное обещание. Затем вы создаете новое обещание из разрешенного значения. return await эффективно ничего не делает. Нет необходимости в дополнительном шаге).

// Don't need to do this 
const test = async _ => {
  return await getOne()
}

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

test()
  .then(value => {
    console.log(value) // 1
  })

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

// Do this instead
const test = _ => {
  return getOne()
}

test()
  .then(value => {
    console.log(value) // 1
  })

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

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

const getOne = async (success = true) => { 
  if (success) return 1
  throw new Error('Failure!')
} 

getOne(false)
  .catch(error => console.log(error)) // Failure!

Если вы хотите обработать ошибку в асинхронной функции, вам нужно использовать 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) // Failure!
  }

  try {
    const two = await getTwo(false)
  } catch (error) {
    console.log(error) // Failure!
  }

  try {
    const three = await getThree(false)
  } catch (error) {
    console.log(error) // Failure!
  }
}

test()

Есть лучший способ.

Мы знаем, что асинхронные функции всегда возвращают обещание. Когда мы вызываем обещание, мы можем обрабатывать ошибки в 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)))

Примечание: Обещание catch Метод позволяет поймать только одну ошибку.

Несколько ожиданий

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

Чтобы показать это в действии, нам нужно создать задержку перед разрешением промиса. Мы можем создать задержку с sleep функция.

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

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

// Using Sleep
console.log('Now')
sleep(1000)
  .then(v => { console.log('After one second') })

сон.gif

скажем getOne занимает одну секунду, чтобы решить. Чтобы создать эту задержку, мы передаем 1000 (одна секунда) в sleep. По прошествии одной секунды и sleep обещание разрешается, мы возвращаем значение 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()

блок-1.gif

Теперь предположим, что вам нужно дождаться трех промисов. Каждое обещание имеет задержку в одну секунду.

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 эти три промиса подряд, вам придется подождать три секунды, прежде чем все три промиса будут разрешены. Это нехорошо, потому что мы заставили 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()

блок-2.gif

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

Есть три шага:

  1. Создайте три обещания
  2. Добавьте все три промиса в массив
  3. await массив промисов с 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()

блок-3.gif

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

Примечание. Эта статья представляет собой измененный отрывок из Изучайте JavaScript. Если вы найдете эту статью полезной, вы можете проверить ее.

Далее мы рассмотрим асинхронные функции и их поведение в циклах.

Спасибо за чтение. Эта статья изначально была размещена на мой блог. Подписаться на моя рассылка если вы хотите больше статей, которые помогут вам стать лучшим разработчиком внешнего интерфейса.

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *