Использование Async/await в Express | Кодементор
Вы заметили, что пишете много асинхронного кода в обработчиках экспресс-запросов? Это нормально, потому что вам нужно взаимодействовать с базой данных, файловой системой и другими API.
Когда у вас так много асинхронного кода, полезно использовать Async/await. Это делает ваш код более понятным.
Сегодня я хочу рассказать, как использовать async/await в обработчике экспресс-запросов.
Примечание. Прежде чем продолжить, вам нужно знать, что такое Async/await. Если вы не знаете, вы можете прочитать эта статья Чтобы получить больше информации.
Использование Async/await с обработчиком запросов
Чтобы использовать Async/await, вам нужно использовать async
ключевое слово при определении обработчика запросов. (Примечание: эти обработчики запросов называются «контроллерами». Я предпочитаю называть их обработчиками запросов, потому что обработчики запросов являются более явными).
app.post('/testing', async (req, res) => {
// Do something here
})
Как только у вас есть async
ключевое слово, вы можете await
что-то сразу в вашем коде.
app.post('/testing', async (req, res) => {
const user = await User.findOne({email: req.body.email})
})
Обработка асинхронных ошибок
Допустим, вы хотите создать пользователя с помощью POST-запроса. Чтобы создать пользователя, вам нужно передать firstName
и email
адрес. Ваша схема Mongoose выглядит так:
const userSchema = new Schema({
email: {
type: String,
required: true,
unique: true,
},
firstName: {
type: String,
required: true,
}
})
Вот ваш обработчик запросов:
app.post('/signup', async(req, res) => {
const { email, firstName } = req.body
const user = new User({ email, firstName })
const ret = await user.save()
res.json(ret)
})
Теперь предположим, что вы отправляете запрос, в котором отсутствует адрес электронной почты, на ваш сервер.
fetch('/signup', {
method: 'post'
headers: { 'Content-Type': 'application/json' }
body: JSON.stringify({
firstName: 'Zell'
})
}
Этот запрос приводит к ошибке. К сожалению, Express не сможет обработать эту ошибку. Вы получите такой журнал:
Чтобы обработать ошибку в асинхронной функции, вам нужно сначала перехватить ошибку. Вы можете сделать это с try/catch
.
app.post('/signup', async(req, res) => {
try {
const { email, firstName } = req.body
const user = new User({ email, firstName })
const ret = await user.save()
res.json(ret)
} catch (error) {
console.log(error)
}
})
Затем вы передаете ошибку в обработчик ошибок Express с параметром next
аргумент.
app.post('/signup', async(req, res, next) => {
try {
const { email, firstName } = req.body
const user = new User({ email, firstName })
const ret = await user.save()
res.json(ret)
} catch (error) {
// Passes errors into the error handler
return next(error)
}
})
Если вы еще не написали собственный обработчик ошибок, Express обработает ошибку за вас с помощью обработчика ошибок по умолчанию. (Хотя я рекомендую вам написать собственный обработчик ошибок. Вы можете узнать больше об этом здесь).
Обработчик ошибок Express по умолчанию:
- Установите статус HTTP на 500
- Отправить текстовый ответ обратно запрашивающей стороне
- Запишите текстовый ответ в консоли
Я использовал Postman для отправки запроса на мой сервер. Вот текстовый ответ от сервера.
Обратите внимание на журнал состояния HTTP 500 на этом изображении. Это говорит мне, что обработчик Express по умолчанию изменил статус HTTP на 500. Журнал принадлежит Моргану. E подробно рассказал о Моргане здесь.
Обработка двух или более асинхронных ошибок
Если вам нужно справиться с двумя await
заявления, вы можете написать этот код:
app.post('/signup', async(req, res, next) => {
try {
await firstThing()
} catch (error) {
return next(error)
}
try {
await secondThing()
} catch (error) {
return next(error)
}
})
Это не нужно. Если firstThing
приводит к ошибке, запрос будет немедленно отправлен обработчику ошибок. Вы бы не инициировали вызов для secondThing
. Если secondThing
приводит к ошибке, firstThing
не вызвал бы ошибку.
Это означает: обработчику ошибок будет отправлена только одна ошибка. Это также означает, что мы можем обернуть все await
заявления в ОДНОМ try/catch
утверждение.
app.post('/signup', async(req, res, next) => {
try {
await firstThing()
await secondThing()
} catch (error) {
return next(error)
}
})
Убираться
Отстойно иметь try/catch
оператор в каждом обработчике запросов. Они делают обработчик запроса более сложным, чем он должен быть.
Простой способ — изменить try/catch
в обещание. Это кажется более дружелюбным.
app.post('/signup', async(req, res, next) => {
function runAsync () {
await firstThing()
await secondThing()
}
runAsync()
.catch(next)
})
Но это муторно писать runAsync
для каждого экспресс-обработчика. Мы можем абстрагировать его в функцию-оболочку. И мы можем прикрепить эту функцию-оболочку к каждому обработчику запросов.
function runAsyncWrapper (callback) {
return function (req, res, next) {
callback(req, res, next)
.catch(next)
}
}
app.post('/signup', runAsyncWrapper(async(req, res) => {
await firstThing()
await secondThing()
})
Экспресс-асинхронный обработчик
Вам не нужно писать runAsyncWrapper
каждый раз, когда вы пишете экспресс-приложение. Алексей Баженов создал пакет под названием экспресс-асинхронный обработчик это делает работу немного более надежным способом. (Это гарантирует next
всегда последний аргумент).
Использовать express-async-handler
вы должны сначала установить его:
npm install express-async-handler --save
Использование его в вашем приложении:
const asyncHandler = require('express-async-handler')
app.post('/signup', asyncHandler(async(req, res) => {
await firstThing()
await secondThing()
})
я не люблю писать asyncHandler
. Это довольно долго. Мое очевидное решение — сократить asyncHandler
к ash
.
Если вы любите, вы можете рассмотреть возможность использования @awaitjs/экспресс по Валерий Карпов. Он добавляет такие методы, как getAsync
а также postAsync
для выражения, поэтому вам не нужно использовать express-async-handler
.
Спасибо за чтение. Эта статья изначально была размещена на мой блог. Подписаться на моя рассылка если вы хотите больше статей, которые помогут вам стать лучшим разработчиком внешнего интерфейса.