了解 node.js 中递归函数的承诺 [英] Understanding promises in node.js for recursive function

查看:19
本文介绍了了解 node.js 中递归函数的承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

SADD 父母.<父母1><parent2>SADD父母.<parent1><祖父母1><祖父母2>...

最终数据应如下所示:

<预><代码>[{标签:<名称>,父母: [{ 标签:<parent1>,父母:[{标签:<祖父母1>},{标签:<祖父母2>}] },{ 标签:<parent2>}]}]

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

var redis = require('node-redis');var r_client = redis.createClient();var Q = require('q');函数 getFromRedis(nodeName){var ret = Q.defer();r_client.smembers('parents.' + nodeName,function(err,val){如果(错误)ret.reject(错误);别的 {varconstructedObject={};//这是我们返回的对象var 依赖=[];如果(值){for (var k in val){//迭代val中的键构造对象.name = val[k];从属.push(getFromRedis(val[k]).then(function(subVal){构造对象[k]=subVal;返回 ret.promise;}));}}否则{返回[]}}Q.all(家属).then(function(){ret.resolve(constructedObject);},ret.reject.bind(ret));});返回 ret;}getFromRedis( 'greg', function(out) {console.log('最终输出:' + JSON.stringify( out ))} );

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

解决方案

  • 在处理 Promise 时尽量保持纯粹.避免具有副作用的函数,即在其自身范围之外操作任何变量.
  • 避免将回调传递给函数.只将它们传递给 promise 方法.您正在使用 r_client.smembers() 和调用 getFromRedis 方法
  • 来执行此操作

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

return [];

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

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

  • 使用 Q.nfcall 辅助函数(等等)以避免直接处理回调风格的 API.使用 then 转换其结果 then - 同步返回树叶或对后代获取计算的承诺.
  • 首先使用Q.all,然后变换其结果.不要为每个依赖添加处理程序,而是在一个步骤中获取整个结果并构建construct.

function getFromRedis(nodeName){返回 Q.ninvoke(r_client, "smembers", 'parents.' + nodeName).then(function(val) {//这是我们返回的对象varconstructedObject = {label: nodeName};如果(瓦尔){var 依赖 = val.map(function(par) {//获得下一级别的承诺return getFromRedis(nodeName+"."+par.toString());});返回 Q.all(dependents).then(function(dependentResults) {构造对象.parents =dependentResults;返回构造对象;});} 别的 {返回构造对象;//没有父母}});}getFromRedis('greg').done(function(out) {console.log('最终输出:' + JSON.stringify( out ));});

I'm trying to use recursive calls to get data out of redis, stopping and returning when the members return 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. Any help would be greatly appreciated.

解决方案

  • Try to be as pure as you can when working with promises. Avoid functions that have side effects, i.e. do manipulate any variables outside of their own scope.
  • Avoid passing callbacks to functions. Do only pass them to promise methods. You are doing this both with r_client.smembers() and when invoking your getFromRedis method

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. You would do ret.resolve([]); return; if at all. However, there are better solutions that let you use return again.

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. Use then to transform its result then - synchronously returning the tree leaves or a promise for the descendant-getting computations.
  • Use Q.all first, and then transform its result. Don't add a handler to each dependent, but get the whole result and build the construct in one single step.

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

这篇关于了解 node.js 中递归函数的承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆