理解node.js中recursion函数的承诺

我试图使用recursion调用从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实现一起工作。 任何帮助将不胜感激。

  • 尝试使用承诺时尽可能地纯粹。 避免有副作用的function,即操作任何variables超出其范围。
  • 避免将callback传递给函数。 只有通过他们承诺的方法。 你正在用r_client.smembers()和调用你的getFromRedis方法来做到这一点

我只能看到一个让你的脚本无法工作的特定错误:

 return []; 

没有任何callback的影响。 所以, ret在这种情况下永远不会被解决。 你会做ret.resolve([]); return; ret.resolve([]); return; 如果有的话。 但是,有更好的解决scheme,让您再次使用return

重构你的脚本,有两点:

  • 使用Q.nfcall帮助函数 (等)来避免直接处理callback式的API。 then使用它来转换它的结果,然后同步返回树叶或承诺后代获得计算。
  • 首先使用Q.all ,然后转换结果。 不要向每个dependent项添加一个处理程序,而是获取整个结果,并在一个步骤中构buildconstruct
 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 )); });