Knex交易承诺警告

时间:2016-12-19 19:32:23

标签: javascript knex.js

我很难与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?
    });
}

但我仍然觉得我可以改进......

1 个答案:

答案 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