当前位置: 首页 > 面试题库 >

了解node.js中对递归函数的承诺

程正阳
2023-03-14
问题内容

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


问题答案:
  • 兑现承诺时,尽量做到纯正。避免使用具有副作用的函数,即不要在其自身作用域之外操作任何变量。
  • 避免将回调传递给函数。仅将它们传递给Promise方法。您正在使用方法r_client.smembers()和调用getFromRedis方法进行此操作

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

return [];

对回调没有任何影响。因此,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 ));
    });


 类似资料:
  • 问题内容: 据我了解,有三种调用异步代码的方法: 活动,例如 回调,例如 承诺 我找到了节点承诺库,但是我不明白。 有人可以解释什么是诺言,为什么我要使用它? 另外,为什么将它从Node.js中删除? 问题答案: node.js中的承诺承诺会做一些工作,然后有单独的回调,将为成功和失败以及处理超时而执行。在node.js中考虑promise的另一种方式是,它们是可能仅发射两个事件的发射器:成功和错

  • 正如标题所解释的,我有一个非常基本的编程问题,但我还没有找到。过滤掉所有(非常聪明的)“为了理解递归,你必须首先理解递归。”各种在线线程的回复我仍然不太明白。 当我们面对不知道自己不知道的事情时,我们可能会提出错误的问题或错误地提出正确的问题。我将分享我的“想法”。我的问题是希望有类似观点的人能够分享一些知识,帮助我打开递归灯泡! 以下是函数(语法用Swift编写): 我们将使用2和5作为参数:

  • 问题内容: 我想遍历HTML 5文件系统中的所有文件,并在迭代完成后开始一些事件。由于这是异步+承诺,我很难尝试掌握其工作方式。 我正在使用angularJS,并创建了一个服务来封装html 5文件系统特定的功能。 这是递归函数: 理想情况下,我想这样调用该函数,并让其返回一个承诺,一旦遍历所有文件,该承诺便会执行。 有什么技巧/想法可以实现吗? 一个想法是拥有一个诺言数组,并为每个文件/目录向该

  • 考虑Python中的这个基本递归: 根据斐波那契数列的(n-1)(n-2)函数,这是有道理的。 Python如何执行包含另一个递归的递归,这个递归不在同一代码行内,而是在同一代码行内?“finobacci(number-1)”是否完成所有递归,直到它到达“1”,然后它对“fibonacci(number-2)”做同样的事情,并将它们相加? 作为比较,下面的递归函数将一个数“x”提升为“y”的幂,我

  • 问题 你想在一个函数中调用相同的函数。 解决方案 使用一个命名函数: ping = -> console.log "Pinged" setTimeout ping, 1000 若为未命名函数,则使用 @arguments.callee@: delay = 1000 setTimeout((-> console.log "Pinged" setTimeout arg

  • 在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。 举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示,可以看出: fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n 所以,fact(n)可以表示为n x fact(n-1),