[英]NodeJS and Mongoose Callback inside a For Loop
这就是问题所在。 我有一个REST API可以处理预订创建,但是,在将预订保存到mongo中之前,它会验证是否与其他预订发生冲突。
exports.create = function(req, res) { var new_type = new Model(req.body); var newBooking = new_type._doc; //check if the new booking clashes with existing bookings validateBooking.bookingClash(newBooking, function(clash){ if(clash == null) // no clashes, therefore save new booking { new_type.save(function(err, type) { if (err) { res.send(err); //error saving } else{ res.json(type); //return saved new booking } }); } else //clash with booking { //respond with "clashDate" } }); };
在这里,您可以使用验证功能来检查同一天的预订是否存在冲突:
exports.bookingClash = function (booking, clash) { //find the bookings for the same court on the same day var courtId = (booking.courtId).toString(); Model.find({courtId: courtId, date: booking.date}, function(err, bookings) { if(err == null && bookings == null) { //no bookings found so no clashes clash(null); } else //bookings found { //for each booking found, check if the booking start hour falls between other booking hours for(var i = 0; i<bookings.length ; i++) { //here is where I check if the new booking clashes with bookings that are already in the DB { //the new booking clashes //return booking date of the clash clash(clashDate); //return the clashDate in order to tell the front-end return; } } //if no clashes with bookings, return null clash(null); } }); };
因此,所有这些都可以与一个新的预订一起使用。 但是,现在我希望能够处理递归预订(每周进行预订)。 我已经重新创建了“创建”函数,并在for loop
调用validateBooking.bookingClash
函数。
不幸的是,当我运行它时,它完美地调用了bookingClash函数,但是当它到达在数据库中进行搜索的那一行时:
Model.find({courtId: courtId, date: booking.date}, function(err, bookings)
它不等待回调,而是在处理响应“冲突”之前使i ++继续运行。
如何使它工作并等待回调?
var array = req.body; var clashes = []; for(var i = 0; i<array.length;i++) { validateBooking.bookingClash(array[i], function(clash) { if(clash) { clashes.push(clash); } else{ console.log("no clash"); } } }
好像是一个基本的异步调用问题,for循环不必等待回调被调用。
您可以使用异步 “系列”函数代替例如for循环。 这样,每个查找将在前一个查找之后被调用。
猫鼬还具有基于诺言的语法,可以帮助您: http : //mongoosejs.com/docs/promises.html
您可以使用异步eachSeries
async.eachSeries(users, function iterator(user, callback) {
if(something) {
//thing you want to do
callback();
} else {
callback();
}
}
由于您正在使用回调函数,因此有两种方法可以尝试解决此问题:1)使用一些外部库,该库允许您执行异步映射操作并针对每个冲突运行所有检查。 一旦完成,请检查合并结果是否冲突,并进行相应的处理,我建议使用异步库
您的代码将类似于: async.map(array,(entry,callback) => validateBooking.bookingClash(entry,callback),(error,mappingResults)=>{...})
2)您可以尝试将此功能更改为递归功能
`function recursiveValidation(arrayToCheck,mainCallback){
if(arrayToCheck.length === 0) {
return cb(null} // end of array without errors
}
validateBooking.bookingClash(_.head(arrayToCheck), function(clash)
{
if(clash)
{
return mainCallback(clash);
}
return recursiveValidation(_.tail(arrayToCheck),mainCallback);
}
}`
上面的代码只是一个模型,但它应该说明这一点。 _是lodash
除了声明使用let代替var之外,无需更改代码中的任何内容,并且循环应该起作用。
var array = req.body; var clashes = [];
`
for(**let** i = 0; i<array.length;i++)
{
validateBooking.bookingClash(array[i], function(clash)
{
if(clash)
{
clashes.push(clash);
}
else{
console.log("no clash");
}
}
}`
您必须了解let和var之间的区别。 也是为什么var无法用于在循环内运行异步代码的原因。 了解有关let的信息: https : //developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/let
在尝试了所有答案之后,我找到了解决方案。
我要做的是:
validateBooking.singleBooking(new_type._doc, newBookingClubId, function (clash) {
if (clash == null) // no clash
{
validatorArray.push(0);
if(validatorArray.length == array.length) //has received everything from mongo
{
console.log("Clashes: " + clashes.toString());
if(validatorArray.indexOf(1) > -1) //contains a clash
{
var error = {
code: 409,
message: "409 Conflict",
clashes: clashes
};
errorsHandler.handleError(error, res);
}
这样,我创建了一个名为“ validatorArray”的数组,每次我收到Mongo的回复时都会调用该数组。
这样,我可以轻松比较预订数组的长度和ValidatorArray的长度。 当它们相等时,这意味着它已经从mongo收到了所有内容,并可以将响应发送回去。
谢谢您的帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.