所以我有这段代码:
Rating.find({user: b}, function(err,rating) {
var covariance=0;
var standardU=0;
var standardV=0;
while (rating.length>0){
console.log("the avarage rating u is:" + avarageRatingU)
console.log("the avarage rating v is:" + avarageRatingV)
currentMovie = rating.pop();
var u=currentMovie.value-avarageRatingU;
standardU = standardU + Math.pow(u,2);
var v=0;
Rating.find({movieid:currentMovie.movieid, user:a}, function(err,ratings) {
if (err) throw err;
if(ratings.length>0){
v=ratings.pop().value-avarageRatingV;
standardV=standardV+Math.pow(v,2);
covariance =covariance+u*v;
console.log(covariance);
}
})
}
console.log(covariance)
callback(null,covariance);
//sim = covariance/(Math.sqrt(standardU)*Math.sqrt(standardV));
})
问题是当我打印协方差时,它会打印0,因为打印在计算之前发生。我想过使用async.series,但是,我不能在while循环中使用回调函数。
任何提示将不胜感激。
Ty:)
答案 0 :(得分:2)
难道你不能像这样在循环内调用你的回调吗?不确定这是否对您有所帮助。
while (rating.length>0){
console.log("the avarage rating u is:" + avarageRatingU)
console.log("the avarage rating v is:" + avarageRatingV)
currentMovie = rating.pop();
var u=currentMovie.value-avarageRatingU;
standardU = standardU + Math.pow(u,2);
var v=0;
Rating.find({movieid:currentMovie.movieid, user:a}, function(err,ratings) {
if (err) throw err;
if(ratings.length>0){
v=ratings.pop().value-avarageRatingV;
standardV=standardV+Math.pow(v,2);
covariance =covariance+u*v;
console.log(covariance);
}
if(rating.length == 0){
console.log(covariance);
callback(null, covariance);
}
})
}
答案 1 :(得分:1)
使用promises或async库将是这种情况下的方式,而不是传统的while循环。由于您已熟悉异步,因此请使用async.map(https://github.com/caolan/async#map)提前获取所需的所有数据。
Rating.find({user: b}, function(err,rating) {
var covariance=0;
var standardU=0;
var standardV=0;
aync.map(rating, function(currentMovie, cb) {
Rating.find({ movieid:currentMovie.movieid, user:a }, function(err,ratings) {
cb(err, ratings);
});
}, function(err, results) {
if (!err) {
// compute covariance with all movie data
}
});
})
答案 2 :(得分:0)
这个怎么样:
Rating.find({user: b}, function(err,rating) {
var covariance=0;
var standardU=0;
var standardV=0;
var c = rating.length; // loop counter
var r = 0; // received counter
function aux_callback (covariance) {
r++;
if (r==c)
callback(null,covariance);
}
while (rating.length>0){
console.log("the avarage rating u is:" + avarageRatingU)
console.log("the avarage rating v is:" + avarageRatingV)
currentMovie = rating.pop();
var u=currentMovie.value-avarageRatingU;
standardU = standardU + Math.pow(u,2);
var v=0;
Rating.find({movieid:currentMovie.movieid, user:a}, function(err,ratings) {
if (err) throw err;
if(ratings.length>0){
v=ratings.pop().value-avarageRatingV;
standardV=standardV+Math.pow(v,2);
covariance =covariance+u*v;
console.log(covariance);
aux_callback(covariance);
}
})
}
//sim = covariance/(Math.sqrt(standardU)*Math.sqrt(standardV));
})
您需要从循环内的lambda函数触发回调,以确保在运行该代码之前不会发生回调。鉴于您似乎需要完成所有循环,我创建了两个计数器c
来跟踪lambda运行的次数,并r
计算你调用aux_callback的次数。此代码应等到您在调用callback
答案 3 :(得分:0)
这是我今晚的第二个承诺解决方案:)。所以,让我试试:
//supposing you are using node js
var Q = require('q'); //https://github.com/dscape/nano
Rating.find({user: b}, function(err,rating) {
var covariance=0;
var standardU=0;
var standardV=0;
var promises = [];
while (rating.length>0){
console.log("the avarage rating u is:" + avarageRatingU)
console.log("the avarage rating v is:" + avarageRatingV)
currentMovie = rating.pop();
var u=currentMovie.value-avarageRatingU;
standardU = standardU + Math.pow(u,2);
var v=0;
var def = Q.defer();
promises.push(def);
Rating.find({movieid:currentMovie.movieid, user:a}, function(err,ratings) {
if (err) {
def.reject();
throw err;
}
if(ratings.length>0){
v=ratings.pop().value-avarageRatingV;
standardV=standardV+Math.pow(v,2);
covariance =covariance+u*v;
def.resolve();
//console.log(covariance);
}
});
}
Q.allSettled(promises, function() {
console.log(covariance);
});
callback(null,covariance);
//sim = covariance/(Math.sqrt(standardU)*Math.sqrt(standardV));
});
答案 4 :(得分:0)
尝试使用Promise!现在Node.js 4.x已经出来了,所有的JavaScript ES6(和Promises)都附带了它。您可以查看Mozilla Foundation文档中的promises here。
如果您以前从未使用过承诺,那么它真正做的就是允许您在值可用之前返回一个值。之后,承诺能够以实际价值成为已解决或被拒绝。
在这种情况下,您将要在new Promise( function(resolve, reject) { ... } )
内封装内部的Rating.find()调用,并在您的promise上附加then()
子句,该子句打印出协方差的值。当您从内部Rating.find()
函数中检索实际协方差时,只需使用 resolve 参数(这是一个采用单个值的函数)并传递协方差,以便将其传递给函数在你的Promise then()
子句中,它将打印协方差。
如果有任何混淆,请给我发表评论!
答案 5 :(得分:0)
你使用哪个 orm ?,我认为更好的方法是按“movieid”对结果进行分组,然后计算每个组的协方差,而不对每个“评级”进行查询结果
Rating.find({user: b}, function(err, rating){
var covariance=0;
var standardU=0;
var standardV=0;
var ratingsByMovieId = groupByMovieId(rating);
while(rating.length > 0){
console.log("the avarage rating u is:" + avarageRatingU)
console.log("the avarage rating v is:" + avarageRatingV)
currentMovie = rating.pop();
var u=currentMovie.value-avarageRatingU;
standardU = standardU + Math.pow(u,2);
var v=0;
ratingsByMovieId[currentMovie.movieid].forEach(function(ratings){
// this code isn't asynchronous :)
// because the code isn't asynchronous you don't need a callback.
});
}
});
function groupByMovieId(ratings) {
var groups = {};
ratings.forEach(function(rating){
var movieId = rating.movieid;
groups[movieId] = groups[movieId] || [];
groups[movieId].push(rating);
});
return groups;
}
我没有测试此代码jeje:)
答案 6 :(得分:0)
假设评级(或评级)是一个数组,你需要迭代并在每个项目上调用异步函数(例如Rating.find),async.eachSeries可能最有意义。
async.eachSeries(ratings, function iterator(rating, callback) {
// invoke async function here for each rating item
// and perform calculations
}, function done() {
// all async functions have completed, print your result here
});
此处有更多文档:https://github.com/caolan/async
答案 7 :(得分:0)
这是在循环中调用异步函数的标准问题。
让我们先看一个更简单的例子。假设我想要一个在for循环中打印i
值的函数,我希望它以异步方式运行:
for (i = 0; i < 5; i++) {
setTimeout(function() { console.log(i); }, 1);
}
现在实际只会打印5次,5次。这是因为异步函数setTimeout
在循环结束后返回,并且i
在执行时的值为5.如果我们希望它打印出0 - 4,那么我们需要做以下事情:
for (i = 0; i < 5; i++) {
(function(i) {
setTimeout(function() { console.log(i); }, 1);
})(i);
}
注意匿名函数如何将i
作为参数。这创造了一个“拯救”的关闭。调用时i
的值。
现在回到你的问题:
covariance = covariance + u * v;
这发生在您的console.log(covariance)
语句之前,这意味着您的打印语句在计算后实际 。这意味着此时covariance
实际上等于0。
您的covariance
变量已初始化为0. u
和v
也是如此。 0 + 0 * 0 = 0.好的,很好:所以如果u
和v
未正确设置,至少数学会检出。
让我们回到你的循环:
while (rating.length>0){
currentMovie = rating.pop();
var u=currentMovie.value-avarageRatingU;
var v=0;
Rating.find({movieid:currentMovie.movieid, user:a}, function(err,ratings) {
if (err) throw err;
if(ratings.length>0){
v=ratings.pop().value-avarageRatingV;
standardV=standardV+Math.pow(v,2);
covariance =covariance+u*v;
...
在这里,我们可以看到您的异步Rating.find
回调正在提取u
的最后一个已知值,即其在while循环的 end 处的值。在v
回调之外定义Rating.find
的确没有任何理由。
如果你想为每个循环设置u
的值,请尝试将其包装在一个匿名的自执行函数中以保存&#34;价值,如下:
Rating.find({user: b}, function(err,rating) {
var covariance = 0;
var standardU = 0;
var standardV = 0;
var u = 0;
while (rating.length > 0){
console.log("the avarage rating u is:" + avarageRatingU)
console.log("the avarage rating v is:" + avarageRatingV)
currentMovie = rating.pop();
u = currentMovie.value - avarageRatingU;
standardU = standardU + Math.pow(u, 2);
(function(u) {
Rating.find({ movieid: currentMovie.movieid, user: a }, function(err, ratings) {
if (err) throw err;
if (ratings.length > 0) {
var v = ratings.pop().value - avarageRatingV;
standardV = standardV + Math.pow(v,2);
covariance = covariance + u * v;
console.log(covariance);
}
});
})(u);
}
console.log(covariance)
callback(null,covariance);
//sim = covariance/(Math.sqrt(standardU)*Math.sqrt(standardV));
});
我还在你的循环之外移动了u
的声明(在里面声明它们是不好的做法,因为你每次都要重新实例化变量)。我在v
回调中移动了Rating.find
的声明,因为它甚至没有在那里使用。