Асинхронный 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
в sleep
JavaScript будет ждать одну секунду, прежде чем разрешить промис.
// Using Sleep
console.log('Now')
sleep(1000)
.then(v => { console.log('After one second') })
скажем 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()
Теперь предположим, что вам нужно дождаться трех промисов. Каждое обещание имеет задержку в одну секунду.
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()
Если getOne
, getTwo
а также getThree
могут быть получены одновременно, вы сэкономите две секунды. Вы можете получить эти три промиса одновременно с Promise.all
.
Есть три шага:
- Создайте три обещания
- Добавьте все три промиса в массив
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()
Это все, что вам нужно знать об основных асинхронных функциях! Я надеюсь, что эта статья прояснит для вас ситуацию.
Примечание. Эта статья представляет собой измененный отрывок из Изучайте JavaScript. Если вы найдете эту статью полезной, вы можете проверить ее.
Далее мы рассмотрим асинхронные функции и их поведение в циклах.
Спасибо за чтение. Эта статья изначально была размещена на мой блог. Подписаться на моя рассылка если вы хотите больше статей, которые помогут вам стать лучшим разработчиком внешнего интерфейса.