for 循环 异步 求助!!
 发布于 11 年前  作者 hsh075623201  6199 次预览  最后一次回复是 11 年前  来自  

根据条件查询数据库,得到一个数据集合,然后再根据数据集合进行循环查询。。形如如下格式:

users.find({userId:""},function(err,userCollection){// for(var i=0 ;i<userCollection.length;i++){ roles.find({roleId:userCollection[i].roleId},function(err,roleCollection){// for(var j =0 ;j<roleCollection.length;j++){ actions.find({actionId:roleCollection[j].actionId},function(err,actionCollection){// redis.set(userCollection[i].id,JSON.stringify(actionCollection)) }) } }) } } 但是 这种方式 感觉 存在问题 ,请问应该如何实现??

22 回复
jiangzhuo

樓上要實現一個什麼效果 從你的描述看,可能的問題就是執行玩循環後 循環內部的一些回調都還沒有調用

异步的循环要自己保证好状态的,这样子肯定是不行的
可以使用async之类的库

hsh075623201

我的 目的 是要 根据 用户 查找其 用户角色 再根据用户角色 查找对应的角色权限 ,但是由于用户 角色 权限 她们之间是多对多的关系 所以需要循环查询。。最终的目的 是获取用户具有哪些权限 ,但是由于是异步处理,上述方案感觉会存在问题(没实验验证),首先请问上述方案存在 问题吗 ,其次是有更好的实现方式吗 ?

hsh075623201

请问 都是采用同步方式获取数据吗?

kingapple

@hsh075623201 这么多循环,不头大么?赶脚亲的代码有bug

@hsh075623201 还是异步的把,不过要有个状态,标记执行结束

hsh075623201

@kingapple 我也 感觉有问题 ,所以在寻求帮助。。。

hsh075623201

@fantasyni 我找到 你提供的async库 的方法了,现正在看。。。

yidahis

我以前遇到的问题和你类似:比如有2张表,user 和 posts,从posts查询完得到一个数组之后要到user获取相应的用户信息。开始我也是像你那样写的,但是发现不行,后来我就用了node自带的 event 模块,注册事件并监听就ok了。

SnipeV5

看看朴灵的 EventProxy 地址:https://github.com/JacksonTian/eventproxy 这个应该用异步编程的发布/订阅模式,朴灵的EventProxy很好用的,我们这个中文社区就用的EventProxy

hsh075623201

现准备尝试async 中waterfall 方法 ,如不行再使用event模块。。。

hsh075623201

我一开始也是想到朴灵的 EventProxy 但是从网上的资料看 ,没发现有参数传递的,请问它具有参数传递的功能吗?

racyily

这是node.js中比较著名的一个问题了,主要是异步和闭包相关的,可以这样写 users.find({userId:""},function(err,userCollection) {// for (var i = 0; i < userCollection.length; i++) { (function (idx) { roles.find({roleId: userCollection[idx].roleId}, function (err, roleCollection) {// for (var j = 0; j < roleCollection.length; j++) { actions.find({actionId: roleCollection[j].actionId}, function (err, actionCollection) {// redis.set(userCollection[idx].id, JSON.stringify(actionCollection)) }) } }) })(i); } });

用一个自执行的function把外层for循环里面的东西包起来,把i当做参数传给function,那idx其实就是i,这样的话idx的值就可以保存下来并被里面的操作正确的访问到了。否则因为异步的原因,你里面的操作每次取到i的值是最后一次i的值。理解了闭包和异步对于学习node进步会很明显,楼主加油。

359056163

楼主 你应该再学学MongoDB。 MongoDB里就有抓取对应的模型的方法。 比如 与一条用户信息(userInfo)对应有N个角色信息(roles),可以使用某个字段将两种模型关联起来,就是$ref 属性 比如 userInfo.admin={$ref:‘roles’,$id:【roles集合内某文档的_id的值】}。 在查询到这条信息时,你可以使用这个属性抓取对应的role文档. 这里只是一个提示,具体的操作方法 请楼主自己搜索!

359056163

其实,本人使用的是mongoosejs在对付此类问题时就很简单。楼主可以看一下这个。 http://mongoosejs.com/docs/populate.html 如果你看了这个,楼主 你会豁然开朗。

jiangzhuo

嗯 說的對 沒有注意他最內層還有用到i 樓主都套了三層 還是用點async什麼的吧

hsh075623201

其实 我本来也想使用此方法的,但是出现如下问题: http://cnodejs.org/topic/538568fea087f45620d07847 由于是初学者,实在找不到原因,所以就放弃了。。。望解答,万分感谢!!

hsh075623201

@jiangzhuo 现使用async 如下所示 但感觉仍不是 很好,请指教。 async.waterfall([ function(callback){ Users.findOne({userId:user.userId},function(err,userCollection){

                        callback(null, userCollection.roleId);
                    });

                },
                function(RoleIdCol, callback){
                    var count = RoleIdCol.length;
                    if(RoleIdCol == undefined||RoleIdCol.length==0){
                        callback(null, "");
                    }
                    for(var i =0 ;i<RoleIdCol.length;i++){
                        Role.findOne({roleId:RoleIdCol[i]},function(err,roleCollection){
                            if(roleCollection.actionId.length!=0){
                                arrayRole.push(roleCollection.actionId);
                            }else{
                                count--;
                            }
                            if(arrayRole.length ==count){
                                callback(null, arrayRole);
                            }
                        })
                    }
                }
            ], function (err, result) {
                //result保存的都是权限Id 

            });
hsh075623201

由于是初学者,对于闭包还不怎么了理解,正在学习中,感谢提供解决方案!

zxc122333
var userCollection = yield users.find({userId:""})
for(var i=0 ;i<userCollection.length;i++){
    var roleCollection = yield roles.find({roleId:userCollection[i].roleId});
    for(var j =0 ;j<roleCollection.length;j++){
        var actionCollection = yield actions.find({actionId:roleCollection[j].actionId});
        redis.set(userCollection[i].id,JSON.stringify(actionCollection))
    }
}
hsh075623201

学习了,第一次看到使用yield的方式。。。

dotnil

也可以试试 promise,也可以把移步调用的部分抽离出来放到独立的 function 里面,确保回调执行时外部闭包的状态是正确的