#node.js #sql-server #asynchronous #promise #es6-promise
#node.js #sql-сервер #асинхронный #обещание #es6-обещание
Вопрос:
Я новичок в node.js и у меня возникла проблема с подключением к mssql
базе данных и подготовкой / выполнением подготовленной инструкции.
У меня есть следующий код:
this.connectionPool.connect().then(pool => {
// Create prepared statement
stmt = new mssql.PreparedStatement(pool);
// PREPARE
stmt.prepare(command, err => {
//TODO: check for errors in prepare
// EXECUTE
stmt.execute((err, result) => {
//TODO: check for errors in execute
// UNPREPARE
stmt.unprepare(err => {
//TODO: check for errors in unprepare
});
console.log(`Rows affected: ${stmt.rowsAffected}`);
console.log(`Result: ${result}`);
return resu<
});
});
}).catch(err => {
console.log(`Connection pool error: ${err}`);
}).finally(() => {
// Close connection
console.log("Closing connection.");
if (this.connectionPool.connected) {
this.connectionPool.close();
}
});
Я обнаружил, что finally()
обещание выполняется одновременно с then()
, чего я бы не ожидал. Это приводит к закрытию соединения до того, как оператор может быть подготовлен.
ConnectionError: connection is closed
Как я могу гарантировать, что соединение будет закрыто только после выполнения инструкции?
Ответ №1:
Обратные вызовы выполняются асинхронно, поэтому вам нужно добавить результат execute
в цепочку обещаний:
this.connectionPool.connect().then(pool => {
// Create prepared statement
stmt = new mssql.PreparedStatement(pool)
// return a promise to add it to the promise chain
return new Promise((resolve, reject) => {
stmt.prepare(command, err => {
// TODO: check for errors in prepare
if (err) {
reject(err)
return
}
// EXECUTE
stmt.execute((err, result) => {
// TODO: check for errors in execute
if (err) {
reject(err)
return
}
// UNPREPARE
stmt.unprepare(err => {
// TODO: check for errors in unprepare
if (err) {
reject(err)
}
})
console.log(`Rows affected: ${stmt.rowsAffected}`)
console.log(`Result: ${result}`)
resolve(result)
})
})
})
}).catch(err => {
console.log(`Connection pool error: ${err}`)
}).finally(() => {
// Close connection
console.log('Closing connection.')
if (this.connectionPool.connected) {
this.connectionPool.close()
}
})
Если stmt.prepare
обещание поддержки готово из коробки, вы можете вернуть его, не оборачивая в new Promise
Все обещанные версии:
this.connectionPool.connect().then(pool => {
// Create prepared statement
stmt = new mssql.PreparedStatement(pool)
return stmt.prepare(command)
.then(() => stmt.execute())
.then((result) => {
console.log(`Rows affected: ${stmt.rowsAffected}`)
console.log(`Result: ${result}`)
})
.finally(() => stmt.unprepare())
}).catch(err => {
console.log(`Connection pool error: ${err}`)
}).finally(() => {
// Close connection
console.log('Closing connection.')
if (this.connectionPool.connected) {
this.connectionPool.close()
}
})
Комментарии:
1. Я считаю, что
stmt.prepare
,stmt.execute
иstmt.unprepare
возвращаетPromise
, если обратный вызов опущен. Не могли бы вы показать мне, как это можно использовать вместо дополнительнойnew Promise
оболочки?2. С помощью этого примера я обнаружил, что теперь ни методы
catch()
orfinally()
не выполняются, что означает, что соединение никогда не закрывается.3. Обновленный ответ. Если этот блок не выполняется, проверьте последний, который выполняется. Я думаю, что проблема могла возникнуть до вызова этого фрагмента кода
4. В вашем втором примере я нахожу, что
stmt.unprepare()
изfinally()
метода выполняется раньшеstmt.prepare()
, и я получаю ошибкуPreparedStatementError: statement is not prepared. Call prepare() first.
. Это в основном то же самое, что я получал ранее, когдаfinally()
метод выполнялся первым и закрывал соединение. Почемуfinally()
не дожидается завершенияthen()
?5. Не могли бы вы проверить, что возвращает метод prepare? Я думаю, что это не обещание, по этой причине оно не ожидается
Ответ №2:
Все методы .prepare()
, .execute()
и .unprepare()
принимают обратные вызовы. Если эти методы не «обещаны», this.connectionPool.connect().then().catch().finally()
цепочка не имеет средств для получения информации о результатах процесса подготовки-выполнения-неподготовленности.
Процесс подготовки-выполнения-неподготовленности может быть обещан следующим образом:
this.connectionPool.connect()
.then(pool => {
let stmt = new mssql.PreparedStatement(pool);
return new Promise((resolve, reject) => {
stmt.prepare(command, err => {
if(err) {
reject(err);
} else {
stmt.execute((err, result) => {
if(err) {
reject(err);
} else {
stmt.unprepare(err => {
if(err) {
reject(err);
} else {
resolve(result);
}
});
}
});
}
});
});
})
.catch(err => {
console.log(`Prepared statement error: ${err.message}`);
})
.finally(() => {
if (this.connectionPool.connected) {
this.connectionPool.close();
}
});
Теперь блоки catch()
и finally()
будут упорядочены так, как вы ожидаете.
Комментарии:
1. Если
.prepare()
(и другие методы) возвращают Promise, как вы сказали выше, тогда все становится намного проще.