Короче говоря : вы не ожидаете con.connection
и con.query
, поэтому внешний код продолжает и вызывает con.close
и возвращает результат внешнего интерфейса, а затем con.query
пытается отправить запрос через закрытое соединение, приводящее к этому исключению.
Вы пишете асин c функций, но вы сделали их только "полусинными c".
Например, это не сработает:
async function getStuff () {
stuff.get(function (err, data) {
if (err) throw err // kills your process if it happend!
return data.stuff // returns to nowhere
})
}
// later on:
const stuff = await getStuff()
console.log(stuff) // prints undefined!
... потому что, по сути, ваша асин c функция просто синхронно вызывает другую функцию (не ждет ее), а затем сразу ничего не возвращает (т.е. undefined
):
async function getStuff () {
stuff.get(...)
// as you can see, no return inside getStuff
}
И позже, обратный вызов, который вы прошли, будет запущен, но затем поезд вашего внешнего кода уже покинул платформу.
Вместо этого вы должны иметь stuff.get
вернуть обещание (большинство современных библиотек сделают это, даже если они дополнительно предоставляют обещание обратного вызова для совместимости со старыми кодовыми базами) и await
it:
async function getStuff () {
const data = await stuff.get() // waits for the stuff to come back
return data.stuff // actually returns the stuff
// The `if (err) throw err` now became unnecessary as well
}
// later on:
const stuff = await getStuff()
console.log(stuff) // prints the stuff!
Если ваша библиотека SQL предоставит обещание интерфейс, вы могли бы просто await
это. Вы написали, что используете mysql2
. Эта библиотека имеет интерфейс обещаний, если требуется с require('mysql2/promise')
. Я бы предложил переключиться на интерфейс обещания вместо интерфейса обратного вызова!
Существует также способ «обновить» существующее con
соединение с интерфейсом обещания: con.promise()
. Таким образом, вы просто сделаете con = DAL.getConnection().promise()
вместо con = DAL.getConnection()
.
Затем вы можете переписать код следующим образом (или эквивалентным, в зависимости от того, какую библиотеку вы выберете):
async function sessionExtend(con, session_id, user_id) {
try {
await con.connect()
await con.query(qryDict.SQL_QUERIES.setUpdateExtendSession, [session_id, user_id])
return JSON.stringify({ result: true, message: 'success' })
} catch (err) {
return JSON.stringify({ result: false, message: err.toString() })
}
}
РЕДАКТИРОВАТЬ: Следующая часть фактически устарела, потому что mysql2
позволяет обновить существующее соединение с интерфейсом обещаний, но я все равно оставлю это здесь на случай, если это поможет кому-то еще в похожая ситуация!
Если вы не можете переключиться на интерфейс обещания, вы можете вместо этого обещать существующие вызовы (хотя это выглядит немного более запутанным):
const { promisify } = require('util')
async function sessionExtend(con, session_id, user_id) {
try {
await promisify(con.connect).call(con)
await promisify(con.query).call(con, qryDict.SQL_QUERIES.setUpdateExtendSession, [session_id, user_id])
return JSON.stringify({ result: true, message: 'success' })
} catch (err) {
return JSON.stringify({ result: false, message: err.toString() })
}
}
util.promisify
оборачивает функцию, которая ожидает обратный вызов (err, data)
, преобразуя ее в asyn c функцию, которая вместо этого возвращает обещание. Поскольку con.query
и соавт. это методы для con
, они должны сохранять этот контекст, поэтому я написал promisify(con.query).call(con, ...)
вместо promisify(con.query)(...)
.