首页 > 这段代码如何用async改写?如何跨层传递res,req

这段代码如何用async改写?如何跨层传递res,req

app.get("/loginForm?**",function(req,res){
        pool.getConnection(function(err,connection){
        if (err) {
            console.log(err+"--from connection");
            res.send("登录失败,数据库连接错误");
        } else{
            connection.query("USE userInfo",function(err,rows){
                if (err) {
                    console.log(err+"--from using database");
                    res.send("登录失败,数据库使用错误");
                }
            else{
                    var selectQuery = "SELECT * FROM users WHERE userName="+"'"+req.query.username+"'";
                    connection.query(selectQuery,function(err,rows){
                        if (err) {
                            console.log(err+"--from query");
                            res.send("登录失败,数据库查询错误");
                        } else{
                                    if (rows.length==0) {
                                        res.send("登录失败,用户不存在");
                                    } else{
                                        if (req.query.password==rows[0].password) {
                                            res.cookie("username",req.query.username,{
                                                expires: new Date(Date.now() + 900000),
                                                httpOnly:true
                                            });/*res.cookie end*/
                                            res.send("登录成功");
                                        } else{
                                            res.send("登录失败,密码不正确");
                                        }
                                    }
                        }
                    });
                }
            });
        }
        if(connection){connection.release()};
    });
});

回调嵌套太多层导致很难维护了


根据一楼的回答我去实验了一下,首先是代码

 //先promise化pool.getConnection
    var getConn = new Promise(function(resolve,reject){
        pool.getConnection(function(err,connection){
            if (err) {
                reject(err);
            } else {
                resolve(connection);
            }
        });
    });
    
   const test = async()=>{
        let connection = await getConn;
        console.log(connection);
    };
    
    

这段直接运行会说async undefined
于是我把它babel一下

var _this = this;

var test = function test() {
        var connection;
        return regeneratorRuntime.async(function test$(context$1$0) {
                while (1) switch (context$1$0.prev = context$1$0.next) {
                        case 0:
                                context$1$0.next = 2;
                                return regeneratorRuntime.awrap(getConn);

                        case 2:
                                connection = context$1$0.sent;

                                console.log(connection);

                        case 4:
                        case "end":
                                return context$1$0.stop();
                }
        }, null, _this);
};

运行test()后报错,说regeneratorRuntime undefined,我用的node5.6,不知道问题出在哪里


原来是因为babel依赖一个babel-polyfill的模块,require一下就好了。。。 但是新的问题又来了,pool.getConnction很容易就promise化了,但是connection.query由于依赖前者传回的connection,所以必须在async函数内部promise化才能使用。。。这就蛋疼了

const test = async()=>{
        let connection = await getConn;
        var conn = new Promise(function(resolve,reject){
            connection.query("USE userInfo",function(err,rows){
                if (err) {
                    reject(err);
                } else {
                    resolve(rows);
                }
            });
        });
        let rows = await conn;
        console.log(rows);
    };
    

所以就变成这个造型了。。。。有什么办法能把connection.query在外部进行promise化么?


次最终方案出来了,如下

app.get("/loginForm?**", async (req, res) => {
        try {
            let connection = await getConn;

            //promise化connection.query
            var conn = function(queryString) {
                var connPromise = new Promise(function(resolve, reject) {
                    connection.query(queryString, function(err, rows) {
                        if (err) {
                            reject(err);
                        } else {
                            resolve(rows);
                        }
                    });
                });
                return connPromise;
            };

            await conn("USE userInfo");

            let selectQuery = "SELECT * FROM users WHERE userName=" + "'" + req.query.username + "'";
            let rows = await conn(selectQuery);

            if (rows.length === 0) throw '登录失败,用户不存在';
            if (req.query.password !== rows[0].password) throw '登录失败,密码不正确';

            res.cookie('username', req.query.username, {
                expires: new Date(Date.now() + 15 * 60 * 1000),
                httpOnly: true
            });
            res.send("登录成功");

            connection.release();
        } catch (e) { res.send(e); }
    });
    

将其babel之后运行成功,为什么是次最终,主要是因为connection.query的promise化写在了主函数里面,显得代码很丑,希望能找到最终方案,让我通关回调地狱QAQ


async/await只对 Promise 对象才有效。首先你要把数据库部分的各个方法改成 Promise 形式的。然后主函数就很简单了:

app.get("/loginForm?**", async(req, res) => {
    try {
        if(!(req.query && req.query.username && req.query.password)) throw new Error('登录失败');
    
        let connection = await pool.getConnection();
        await connection.query("USE userInfo");
        
        let selectQuery = "SELECT * FROM users WHERE userName=" + "'" + req.query.username + "'";
        let rows = await connection.query(selectQuery);
    
        if(rows.length === 0) throw new Error('登录失败,用户不存在');
        if(req.query.password !== rows[0].password) throw new Error('登录失败,密码不正确');
    
        res.cookie('username', req.query.username, {
            expires: new Date(Date.now() + 15 * 60 * 1000),
            httpOnly: true
        });
        res.status(200).send("登录成功");

        connection.release();
    } catch(e) {
        res.status(401).send(e.message);
    }
});

别忘了这里的pool.getConnection()connection.query() 都要 Promise 化。reject(err)会被catch(e)捕捉到,各种错误说明也是写在调用方法中的。

对了,不管怎么样,原文哪种if(err)-else都是不需要的。对于这种有错就终止/返回函数的情况,只需要判断错误,不需要else


一楼已经给出了终极答案,我也只是用过co库,还没有怎么尝试await/async语法。
不知道楼主有没有理解一楼的代码,如果没有理解,可以先尝试完全Promise 化,之后理解Generator函数, 然后理解一下co库的基本原理,按照这个线路再去使用await/async 语法之后,应该会易懂很多吧。

另外,你说的async包 我用过,不过这东西在await/async语法面前还是太啰嗦了。await/async才是解决nodejs异步问题的终极方案。

还有,else多了,确实很恶心。建议函数尽早返回

function(foo){
    if(!foo){
        return new Error("undefined");
    }
    
    if(foo==="bar"){
        return new Error("one case");
    }
    
    if(foo==="demo"){
        return new Error("another case");
    }
    
    doSomethings(foo);
    
}
【热门文章】
【热门文章】