我express框架做blog的过程中遇到个很纠结的问题,我的mongo数据库里有两张表,
一个是存储用户信息的user表,字段是_id,email,name,password等…
一个是存储文章的blog表,字段是_id,title,content,author_id等…
blog表里的每篇文章除了标题内容等之外还有个命名为author_id的字段,存储文章作者id。
我现在想循环blog表,读取所有文章,找到每篇文章的author_id,
然后根据该author_id读取user表里的name字段,该字段表示作者名称。
但是在循环过程中发现读不到每个for循环时的序列值,只能拿到最后for结束后的序列值。
这是因为数据库查询是异步的,采用回调的方式处理。
这种情况下,我怎么拿到每次for循环的值呢?下面是代码:
module.exports = function(req, res) { var blog = require(’…/models/blog’); var user = require(’…/models/user’); var session_user = req.session.user; var condition = session_user? {author_id: session_user._id} : null;
blog.get(null, function(status, message) {
for (var i=0, count=message.length; i<count; i++) {
var label_arr = message[i].label.split(',');
var j = 0;
var num = label_arr.length;
var new_arr = [];
for (; j<num; j++) {
var k = 0;
var label_arr2 = label_arr[j].split(',');
var len = label_arr2.length;
for (; k<len; k++) {
var clean_elem = label_arr2[k].replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g,'');
if (clean_elem != '') {
new_arr.push(clean_elem);
}
}
}
message[i].label = new_arr;
user.get({_id: message[i].author_id}, function(status, user_message) {
//这个回调函数只能被调用一次,根本拿不到对应用户的name值,我咧个去,纠结死了。。。
message[i].author_name = user_message[0].name; //这里出错,i的值永远是count
blog.get(condition, function(status, self_message) {
res.render('index', {
title: 'NodeJs学习站',
type: 'index',
loginer: session_user,
blog: message,
self_blog: self_message
});
});
});
}
});
};
你这个javascript绑定的变量发生变化的问题 用下面这种方式解决,一定要用下面这个方式绑定一下变量。
function (i){ do(i); }(i变量绑定)
多看看javascript基础吧,js的坑还是很多的,除了这个,比较有名的还有this关键字,建议看看javascript高级程序设计。
你这种方法,我已经试过了,是不行的。
这个是典型的用同步的思路去写异步的程序,楼上的闭包可以解决问题,但是看上去比较怪异,难以理解。 最简单的用list的forEach来实现。 message.forEach(function(msg){ … … … user.get({_id: msg.author_id}, function(status, user_message) {}) … … … })
是的,这是更好的方式
你这种闭包写法也要分场合的,不是什么地方都能用啊
@hnliji1107 分什么场合?
谢谢,我试下forEach。
我试了下,最后得到的还是只有一个结果,forEach跟for循环是一样的,附上user.get方法:
//查询用户信息 User.get = function(condition, callback) { if (condition && condition._id) { condition._id = new ObjectID(condition._id); }
User.base(function(collection) {
collection.find(condition).toArray(function(err, user) {
if (err) {
return callback(0, err);
}
return callback(1, user);
});
});
};
这代码看的好累,你在异步循环里面调用 res.render?
是的,因为res.reder需要异步请求的数据。
@hnliji1107 res.reder只能调用一次吧
@hnliji1107 res.render不能调用多次的。如果想把多次调用de结果输出到前端,可以在外面放一个数组变量,然后在每次de循环调用取数据的时候push结果到外面的数组,最后再render。