【问题标题】:Understanding promises in node.js for recursive function了解 node.js 中用于递归函数的 Promise
【发布时间】:2013-09-20 12:12:57
【问题描述】:

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

所以我的数据是这样添加的:

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

最终的数据应该是这样的:

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

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

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 ))} );

我可以查看示例并从理论上了解它应该如何工作,但我不知道它应该如何与 q 实现一起工作。任何帮助将不胜感激。

【问题讨论】:

  • 您之前是否有基于回调的解决方案?
  • 没有。我试过了,但它要复杂得多。

标签: javascript node.js recursion promise


【解决方案1】:
  • 在处理 Promise 时尽量保持纯洁。避免使用具有副作用的函数,即在其自身范围之外操作任何变量。
  • 避免将回调传递给函数。只将它们传递给 promise 方法。您正在使用 r_client.smembers() 和调用 getFromRedis 方法时这样做

我只能看到一个特定的错误会使您的脚本无法正常工作:

return [];

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

要重构你的脚本,有两点:

  • 使用Q.nfcall helper function(等)来避免直接处理回调样式的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 ));
});

【讨论】:

  • 简洁多了。当我看到它像这样工作时,这一切都是有道理的。但是,由于某种原因,当我从命令行运行它时,它永远不会返回任何输出?这就像它陷入了一个循环。
  • 添加一些日志来查看vals 你在这段时间内得到了什么,也许真的有。我不太了解redis,可能是我没有从值中正确构造查询-请参阅代码which I just edited的部分,您可能需要对其进行调整。
  • 嗯。似乎它应该可以工作,但我在 q.js 中遇到错误:TypeError: Object #&lt;Object&gt; has no method 'sendCommand' at exports.commands.forEach.RedisClient.(anonymous function) (/Users/username/node_modules/node-redis/index.js:408:12) at Promise.apply (~/node_modules/q/q.js:1122:26) at Promise.promise.promiseDispatch (~/node_modules/q/q.js:752:41) at Promise.dispatch (~/node_modules/q/q.js:1337:14) at flush (~/node_modules/q/q.js:108:17) at process.startup.processNextTick.process._tickCallback (node.js:244:9)
  • 我改变的一件事(无论哪种方式我都会得到错误):smembers 从 Redis 获取缓冲区而不是字符串。所以我在 'par' 上调用了 toString()。
  • 哦,找到了this。我将 Q.nfcall() 更改为:return Q.ninvoke(r_client, "smembers", 'parents.' + nodeName).then(function(val) { 在三天的大部分时间里,我一直在努力解决这个问题。非常感谢您的帮助。
猜你喜欢
  • 2020-02-10
  • 2016-08-20
  • 2019-11-27
  • 2016-04-09
  • 1970-01-01
  • 2017-09-09
  • 1970-01-01
  • 2015-11-13
相关资源
最近更新 更多