Javascript 无法从函数调用mongodb方法

Javascript 无法从函数调用mongodb方法,javascript,angularjs,mongodb,function,database,Javascript,Angularjs,Mongodb,Function,Database,所以我做了一个用户登录,数据库是mongodb,它工作得非常完美。但是,我想在用户登录后再次调用mongodb,因此我决定将其拆分为单独的函数。但是,当我尝试使用登录脚本并将其转换为函数时,数据库无法打开。这是没有意义的,因为我使用的代码与路线内部的代码完全相同。这可以在函数中完成吗?有人知道发生了什么事吗 下面是证明dB无法打开的调试程序的代码和图像 路线 // Listen for Upload file router.post('/uploadFile', function

所以我做了一个用户登录,数据库是mongodb,它工作得非常完美。但是,我想在用户登录后再次调用mongodb,因此我决定将其拆分为单独的函数。但是,当我尝试使用登录脚本并将其转换为函数时,数据库无法打开。这是没有意义的,因为我使用的代码与路线内部的代码完全相同。这可以在函数中完成吗?有人知道发生了什么事吗

下面是证明dB无法打开的调试程序的代码和图像

路线

   // Listen for Upload file 
    router.post('/uploadFile', function (req, res) {
        upload(req, res, function (err) {
            if (err) {
                console.log("Error uploading file");
            } else {
                //var databaseName = "E-learn", collection = "Accounts";
                var username = req.body.username ; 
                var fileName = req.file.filename ; 
                var filePath = req.file.path ; 
                console.log(username);
                console.log("GET " + req.file.fieldname);
                console.log("GET " + req.file.filename);
                console.log("GET " + req.file.orignalName);
                console.log("GET " + req.file.path);
                var result = findOne(username); 
                res.json(result); 
            }
        });
    });
函数调用

function findOne(username){
    var databaseName = "E-learn", collection = "Accounts";
    var db = new Db(databaseName, new Server('localhost', 27017));
    db.open(function (err, db) {
        console.log(databaseName + ": opened");
        console.log(db);
        db.collection(collection).findOne({username:username}, function (err, doc) {
            assert.equal(null, err);
            if (doc != null) {
                console.log("Found");
                // db.close();
                return "Found" ; 

            } else {
                console.log("Not Found");
                // db.close();
                return "Not found";
            }
            db.close();
        });
    });
console.log("Did not open")
db.close(); 
return 0 ; // Should not be called
}

正如第一次查看时所观察到的,您的代码中有几个问题

  • 在异步函数中使用return返回结果将不起作用。 您需要定义一个回调函数,将其作为findOne的引用传递。需要调用此回调函数以返回结果

  • 在这种情况下,打印“未打开”并不意味着数据库未打开。这是异步执行,所以数据库可以在打印控制台日志后打开


  • 不确定运行的是哪个ES版本,但如果您想采用同步方法,请尝试此版本的findOne。Async/Await使异步代码同步

    async function findOne(username){
        var databaseName = "E-learn", collection = "Accounts";
        var db = new Db(databaseName, new Server('localhost', 27017));
    
        let db = await db.open();
        // try above line first
        //let {err, db} = await db.open();
    
        let doc = await db.collection(collection).findOne({username:username});
        // try above line first
        //let {err, doc} = await db.collection(collection).findOne({username:username});
    
        //assert.equal(null, err);
        if (doc != null) {
            console.log("Found");
            // db.close();
            return "Found" ; 
    
        } else {
            console.log("Not Found");
            // db.close();
            return "Not found";
        }
        db.close();
    
    //console.log("Did not open")
    //db.close(); 
    //return 0 ; // Should not be called
    }
    

    如果Async/Await出现错误,请尝试安装此软件包

    大多数新引入的JavaScript开发人员都会遇到典型的异步回调问题

    首先,(必须为您阅读)。这意味着,当您将函数作为某个对象的参数传递时,您不能期望函数中的代码将内联到代码中运行。可能您传递的函数将作为事件的结果被调用(连接到某物,用户单击按钮,数据库打开…),因此将来某个时候会发生。即使是1纳秒之后,也将是未来

    因此,您希望它以这种方式运行:

    function findOne(username){
        // Start with this (step 1)
        var databaseName = "E-learn", collection = "Accounts";
        // Then continue with this (step 2)
        var db = new Db(databaseName, new Server('localhost', 27017));
        // Open the database (step 3) and the code will wait for the database to open
        db.open(function (err, db) {
            // Run this inline, just after db.open (step 4)
            console.log("OPEN");
            [...]
        });
        // Continue with this after the database was open (step 5)
        console.log("Did not open")
        db.close(); 
        return 0 ; // Should not be called
    }
    
    但实际上发生的是:

    function findOne(username){
        // Start with this (step 1)
        var databaseName = "E-learn", collection = "Accounts";
        // Then continue with this (step 2)
        var db = new Db(databaseName, new Server('localhost', 27017));
        // Open the database (step 3), pass a function that will be called by the database when is open AND continue with the next step
        db.open(function (err, db) {
            // This function will be called when the database is open, so right now is not called.
            console.log("OPEN");
            [...]
        });
        // This is the next step after step 3 (step 4).
        console.log("Did not open")
        db.close(); 
        return 0 ; // Should not be called
    }
    
    // And sometime in the future you suddenly get in console OPEN, when the database decides to run the callback you passed to it.
    
    另一种方法是
    返回总是从函数返回,因此使用此嵌套函数:

    function findOne(username) { // function keyword, so this is a function (number 1)
        [...]
        db.open(function (err, db) { // Note the function keyword here, so this is a function too (number 2)
            [...]
            return 1; // This return actually works, BUT affects the function where it belongs, which is function number 2 in this case.
        });
        [...]
        return 0; // And this one is the return of the function number 1.
    }
    
    因此,假设在运行下一行代码之前,
    db.open
    立即运行回调。尽管它不是以异步方式运行的,但回调中的
    返回
    仍然无法返回
    findOne
    函数

    异步问题需要异步解决方案。(或者使用ES6生成器(async、await等),但目前会使您更加复杂,因为您仍然不了解代码发生了什么,更糟糕的是,何时使用生成器(因为它们与异步回调相关联),所以最好先了解JS中的异步回调)。当你理解它的时候,其实很简单。只是一些变化:

    // Listen for Upload file
    router.post('/uploadFile', function (req, res) {
        upload(req, res, function (err) {
            if (err) {
                console.log("Error uploading file");
            } else {
                //var databaseName = "E-learn", collection = "Accounts";
                var username = req.body.username ; 
                var fileName = req.file.filename ; 
                var filePath = req.file.path ; 
                console.log(username);
                console.log("GET " + req.file.fieldname);
                console.log("GET " + req.file.filename);
                console.log("GET " + req.file.orignalName);
                console.log("GET " + req.file.path);
                // Converted the sync function to an async one, by passing a
                // callback function as a parameter with 2 arguments, being
                // the first the possible error and the second the data
                findOne(username, function(err, result) {
                    if (err) {
                        console.log("Error uploading file");
                    } else {
                        res.json(result);
                    }
                });
            }
        });
    });
    
    // Here you can see now that we have the callback parameter,
    // that references the callback function we passed before and
    // we can call it whenever we want
    function findOne(username, callback) {
        var databaseName = "E-learn", collection = "Accounts";
        var db = new Db(databaseName, new Server('localhost', 27017));
        db.open(function (err, db) {
            if (err) {
                callback(err); // If error, pass the error as first argument of the callback
            } else {
                console.log(databaseName + ": opened");
                console.log(db);
                db.collection(collection).findOne({username:username}, function (err, doc) {
                    if (err) {
                        callback(err); // As findOne is another async callback too, the same as above. Check for err
                    } else {
                        // And if everything is fine, then pass the result as the second parameter of the callback
                        if (doc != null) {
                            callback(null, "Found");
                        } else {
                            callback(null, "Not found");
                        }
                    }
                    db.close();
                });
            }
        });
    }
    
    正如您可能已经注意到的,在数据库方法和路由器方法中,您将大量的
    函数作为回调传递

    以及一些开发人员ProTip:

    • 现在,只需逐行阅读代码,并尝试理解每一行上发生的事情。这样,您可能会想,“为什么我没有编写的代码是由回调生成的,而我的代码不是?”。这个问题和一些研究会对你有很大帮助
    • 总是有干净的压痕。你的代码有一些问题。缩进在JavaScript中是必须的,因为它的异步特性,在JavaScript中可以有一个回调地狱,缩进在这方面帮助很大

    你能修改你的代码并只发布相关的代码片段吗?我感觉到一个竞争条件问题。当findOne被调用时,打开数据库、查找记录并响应需要时间。可能会在完成之前触发res.json()。您是否注释掉了res.json(),只是为了查看在调用DB时是否写入日志?