所以我做了一个用户登录,数据库是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
}
答案 0 :(得分:0)
首次查看时,您的代码中存在几个问题。
在异步函数中使用return来返回结果将不起作用。 您需要定义一个回调函数,您将其作为findOne的引用传递。需要调用此回调函数以返回结果。
在此方案中打印“未打开”并不意味着数据库未打开。这是异步执行,因此数据库可能会在打印完该控制台日志后打开。
答案 1 :(得分:0)
不确定您正在运行的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出现错误,请尝试安装此软件包。 https://www.npmjs.com/package/asyncawait
答案 2 :(得分:0)
您正面临大多数新引入的JavaScript开发人员遇到的典型异步回调问题。
首先,JavaScript is asynchronous(必须为您阅读)。这意味着当您将函数作为某个参数传递时,您不能指望函数内部的代码将内联到代码中。也许您传递的函数将作为事件的结果被调用(连接到某个东西,用户单击按钮,数据库被打开...),因此将来某个时候会发生。即使是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.
另一种研究方法是return
将始终从函数返回,因此具有此嵌套函数:
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
在运行下一行代码之前立即运行回调。虽然它不是以异步方式运行,但回调中的return
仍然无法返回findOne
函数。
异步问题需要异步解决方案。 (或者使用ES6生成器(异步,等待等等),但是目前会让你更加复杂,因为你仍然不知道代码会发生什么,更糟糕的是,何时使用生成器(因为它们被束缚)到异步回调),所以最好先了解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();
});
}
});
}
您可能已经注意到,您在数据库方法和路由器方法内部传递了大量function
作为回调。
一些开发人员说: