简体   繁体   English

理解node.js中的promises for recursive function

[英]Understanding promises in node.js for recursive function

I'm trying to use recursive calls to get data out of redis, stopping and returning when the members return null. 我正在尝试使用递归调用从redis中获取数据,在成员返回null时停止并返回。

So my data is added like this: 所以我的数据添加如下:

SADD parents.<name> <parent1> <parent2>
SADD parents.<parent1> <grandparent1> <grandparent2>
...

And the final data should look like: 最终数据应如下所示:

[
 {
     label: <name>,
     parents: [
         { label: <parent1>,
           parents: [ {label: <grandparent1>}, {label: <grandparent2> }] },
         { label: <parent2> }
     ]
 }
]

Here's the code I'm messing with (sort of cobbled together from different sources), but I have no idea what I'm doing. 这是我正在搞乱的代码(有点从不同的来源拼凑而成),但我不知道我在做什么。 Not sure if this code is even useful, I could be way off track. 不确定这段代码是否有用,我可能会偏离轨道。

var redis = require('node-redis');
var r_client = redis.createClient();
var Q = require('q');


function getFromRedis(nodeName){
        var ret = Q.defer();
        r_client.smembers('parents.' + nodeName,function(err,val){
                if (err) ret.reject(err);
                else {
                        var constructedObject={};  //this is our returned object
                        var dependents=[];
                        if (val)
                        {
                                for (var k in val){  //iterate the keys in val
                                        constructedObject.name = val[k];

                                        dependents.push(getFromRedis(val[k])
                                        .then(function(subVal){
                                                constructedObject[k]=subVal;
                                                return ret.promise;
                                        })
                                        );
                                }
                        }
                        else { return [] }

                }
                Q.all(dependents)
                .then(function(){ret.resolve(constructedObject);},ret.reject.bind(ret));

        });
                return ret;
}

getFromRedis( 'greg', function(out) {console.log('Final output: ' + JSON.stringify( out ))} );

I can look at the examples and see theoretically how it's supposed to work, but I can't get my mind around how it should work with the q implementation. 我可以看看这些例子,从理论上看它应该如何工作,但是我无法理解它应该如何与q实现一起工作。 Any help would be greatly appreciated. 任何帮助将不胜感激。

  • Try to be as pure as you can when working with promises. 在使用promises时尽量保持纯洁。 Avoid functions that have side effects, ie do manipulate any variables outside of their own scope. 避免使用具有副作用的函数,即操作超出其自身范围的任何变量。
  • Avoid passing callbacks to functions. 避免将回调传递给函数。 Do only pass them to promise methods. 只传递给promise方法。 You are doing this both with r_client.smembers() and when invoking your getFromRedis method 您正在使用r_client.smembers()和调用getFromRedis方法执行此操作

I can see only one specific mistake that would keep your script from working: 我只能看到一个会阻止你的脚本工作的特定错误:

return [];

does not have any effect from the callback. 回调没有任何影响。 So, ret is never going to be resolved in this case. 因此,在这种情况下, ret永远不会得到解决。 You would do ret.resolve([]); return; 你会做ret.resolve([]); return; ret.resolve([]); return; if at all. 如果有的话。 However, there are better solutions that let you use return again. 但是,有更好的解决方案可以让您再次使用return

To restructure your script, there are two points: 要重构脚本,有两点:

  • Use the Q.nfcall helper function (and the like) to avoid dealing with callback-style APIs directly. 使用Q.nfcall辅助函数 (等)可以避免直接处理回调式API。 Use then to transform its result then - synchronously returning the tree leaves or a promise for the descendant-getting computations. then使用then转换其结果 - 同步返回树叶或后代获取计算的承诺。
  • Use Q.all first, and then transform its result. 首先使用Q.all ,然后转换其结果。 Don't add a handler to each dependent , but get the whole result and build the construct in one single step. 不要为每个dependent项添加处理程序,而是获取整个结果并在一个步骤中构建construct

function getFromRedis(nodeName){
    return Q.ninvoke(r_client, "smembers", 'parents.' + nodeName).then(function(val) {
        // this is our returned object
        var constructedObject = {label: nodeName};
        if (val) {
            var dependents = val.map(function(par) {
                // get a promise for the next level
                return getFromRedis(nodeName+"."+par.toString());
            });
            return Q.all(dependents).then(function(dependentResults) {
                 constructedObject.parents = dependentResults;
                 return constructedObject;
            });
        } else { 
            return constructedObject; // without parents
        }
    });
}

getFromRedis( 'greg' ).done(function(out) {
    console.log('Final output: ' + JSON.stringify( out ));
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM