理解node.js中的promises for recursive function

cod*_*ero 7 javascript recursion node.js promise

我正在尝试使用递归调用从redis中获取数据,在成员返回null时停止并返回.

所以我的数据添加如下:

SADD parents.<name> <parent1> <parent2>
SADD parents.<parent1> <grandparent1> <grandparent2>
...
Run Code Online (Sandbox Code Playgroud)

最终数据应如下所示:

[
 {
     label: <name>,
     parents: [
         { label: <parent1>,
           parents: [ {label: <grandparent1>}, {label: <grandparent2> }] },
         { label: <parent2> }
     ]
 }
]
Run Code Online (Sandbox Code Playgroud)

这是我正在搞乱的代码(有点从不同的来源拼凑而成),但我不知道我在做什么.不确定这段代码是否有用,我可能会偏离轨道.

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 ))} );
Run Code Online (Sandbox Code Playgroud)

我可以看看这些例子,从理论上看它应该如何工作,但是我无法理解它应该如何与q实现一起工作.任何帮助将不胜感激.

Ber*_*rgi 3

  • 在履行诺言时尽量保持纯洁。避免具有副作用的函数,即在其自身范围之外操作任何变量。
  • 避免将回调传递给函数。只将它们传递给 Promise 方法。您在调用您的方法r_client.smembers()时都执行此操作getFromRedis

我只能看到一个会使您的脚本无法运行的具体错误:

return [];
Run Code Online (Sandbox Code Playgroud)

回调不会产生任何影响。因此,ret这种情况永远不会得到解决。ret.resolve([]); return;如果有的话你会做的。但是,有更好的解决方案可以让您return再次使用。

要重构脚本,有两点:

  • 使用Q.nfcall辅助函数(等)可以避免直接处理回调风格的 API。然后用于then转换其结果 - 同步返回树叶或对后代获取计算的承诺。
  • 先使用Q.all,然后对其结果进行变换。不要向每个添加处理程序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 ));
});
Run Code Online (Sandbox Code Playgroud)

  • 哦,找到了[这个](https://github.com/kriskowal/q#adapting-node)。我将 Q.nfcall() 更改为: `return Q.ninvoke(r_client, "smembers", 'parents.' + nodeName).then(function(val) {` 我一直在用头撞墙三天的大部分时间都在努力解决这个问题。非常感谢您的帮助。 (2认同)