我很难与Knex,交易和Promise合作,并感谢SO专家的帮助:)
通过阅读类似帖子和许多关于Promises的文章,我明白我离解决方案并不太远,但发现以下代码对于这么简单的任务来说真的过于复杂。
这个类只是暴露了一个接收先前构建的查询的函数,并且需要在第一次调用" load_user_settings"之后运行它。功能(使用PostgreSQL 9.5作为数据库)。我实际上需要第二个查询的结果(或错误),所以只需将trx.commit放在"然后"不适合我。
在我的函数结束时的process.nextTick真的感觉像是一个巨大的黑客并被添加,以避免将我的整个应用程序更改为Promises,因为目前这是不可行的。没有它,我经常发现自己有Promise警告(" Unhandled rejection Error")并在我的代码中稍后抛出异常时挂起代码。
另外,我可以不时在日志中看到以下警告: 警告:承诺被拒绝且出现非错误:[object Undefined] 我猜这个警告在某种程度上与这个问题有关......
如果找到仅使用回调的解决方案,那也很好,因为我们的整个应用程序当前正在使用回调。
const pg = require('pg');
const async = require('async');
class MyClass {
constructor(connectionInfo) {
this.connectionInfo = connectionInfo; // This is an object containing user, password, database, host and port.
this.pgKnex = require('knex')({
client : 'pg',
connection : this.connectionInfo,
pool : {
min : 1,
max : 25
}
});
}
query(username, sql, params, callback) {
let response;
let error;
this.pgKnex.transaction((trx) => {
return this.pgKnex.raw(`SELECT load_user_settings(?)`, [username]).transacting(trx)
.then(() => {
return this.pgKnex.raw(sql, params).transacting(trx);
})
.then((result) => {
response = result;
return trx.commit();
}).catch((err) => {
error = err;
console.error(err);
return trx.rollback();
});
}).catch((err) => {
error = err;
console.error(err);
}).then(() => {
process.nextTick(() => {
callback(error, response);
});
});
}
}
module.exports = MyClass;
根据Bergi发表的评论,我写了这个版本,避免了任何黑客行为,并删除了我所有的承诺警告:
query(username, sql, params, callback) {
this.pgKnex.transaction((trx) => {
this.pgKnex.raw(`SELECT set_config('ims.username', ?, false)`, [username]).transacting(trx).asCallback((err, result) => {
if(err) {
trx.rollback().asCallback(() => {
console.error(err);
callback(err);
});
return;
}
this.pgKnex.raw(sql, params).transacting(trx).asCallback((err, result) => {
if(err) {
trx.rollback().asCallback(() => {
console.error(err);
callback(err);
});
return;
}
trx.commit().asCallback((commitErr) => {
callback(commitErr, result);
});
});
});
}).asCallback((err, result) => {
// Nothing to do here ... I guess?
});
}
但我仍然觉得我可以改进......
答案 0 :(得分:0)
让我试着简化:
query(username, sql, params, callback) {
this.pgKnex.transaction((trx) => {
return this.pgKnex.raw(`SELECT set_config('ims.username', ?, false)`, [username])
.transacting(trx)
.then(() => {
return this.pgKnex.raw(sql, params)
.transacting(trx);
});
}).asCallback(callback);
}
使用事务阻止时,您可以返回Promise
,如果Promise
被解决/拒绝,knex将自动提交/回滚。
最后的asCallback(callback)
调用可确保将promise链中抛出的错误传递给callback
。您不需要单独处理每个承诺的错误,因为承诺链的所有错误都会冒泡。同样,如果从第二个sql查询(promise链的最后一个)返回结果,则此结果将作为第二个参数传递给callback
。