【问题标题】:node js / express application - calling a function within a functionnode js / express应用程序-在函数中调用函数
【发布时间】:2016-09-28 21:00:31
【问题描述】:

背景信息

我有一个连接到 Redis 数据库以查询值列表的节点/快速应用程序。然后对于返回数据中的每个值,我需要做进一步的查询。

问题

初始查询(redis“扫描”命令)工作正常,但我为初始结果集中的每个项目尝试的 HGETALL 查询未按预期运行。

为了演示这个问题,我在第 34 行添加了一个 console.log 命令来打印出当前扫描记录的值......然后我在 HGETALL 的回调函数中再次打印出来(第 36 行)但是价值观不同。在我看来,它们应该是相同的......但我确信这是我缺少的关于 node.js 工作方式的基本内容。

代码

 27 router.get('/', function(req, res, next) {
 28         redis.send_command("SCAN", [0,"MATCH", "emergency:*"], function(err, reply) {
 29                 if (reply) {
 30                         var retdata = [];
 31                         console.log('length is: ' + reply[1].length);
 32                         for (var i = 0; i < reply[1].length; i++) {
 33                                 var emergIP = reply[1][i];
 34                                 console.log('emergIP outside the call: ' + emergIP);
 35                                 redis.hgetall(emergIP, function (err, data) {
 36                                         console.log('emergIP inside the call: ' + emergIP);
 37                                         if (data) {             
 38                                                 var temp = emergIP.split(":");
 39                                                 var key = temp[1];
 40                                                 console.log('the key is: ' + key);
 41                                                 //retdata.push({key:data.callerid});
 42                                         }
 43                                 });
 44                         }//end for loop
 45                         res.send(JSON.stringify(retdata));
 46                 } //end if
 47                 else {  
 48                         //no emergency data defined yet
 49                         var retval = {"res":false, "msg":"no emergency data defined"};
 50                         res.send(JSON.stringify(retval));
 51                 
 52                 }             
 53         }); //end send_command
 54 });
 55 

代码输出

length is: 8
emergIP outside the call: emergency:10.1
emergIP outside the call: emergency:10.2
emergIP outside the call: emergency:10.13
emergIP outside the call: emergency:10.14
emergIP outside the call: emergency:10.18.90
emergIP outside the call: emergency:10.19
emergIP outside the call: emergency:10.20
emergIP outside the call: emergency:10.244
GET /emergency/ 200 220.368 ms - 2
emergIP inside the call: emergency:10.244
the key is: 10.244
emergIP inside the call: emergency:10.244
the key is: 10.244
emergIP inside the call: emergency:10.244
the key is: 10.244
emergIP inside the call: emergency:10.244
the key is: 10.244
emergIP inside the call: emergency:10.244
the key is: 10.244
emergIP inside the call: emergency:10.244
the key is: 10.244
emergIP inside the call: emergency:10.244
the key is: 10.244
emergIP inside the call: emergency:10.244
the key is: 10.244

问题

我认为问题在于我期望 send_command 函数上的回调按顺序发生。换句话说,也许问题是我不应该在另一个函数调用中进行函数调用? 这是我的第一个节点应用程序......我正在学习。

任何建议将不胜感激。

【问题讨论】:

  • @amitmah,是的,我认为你是对的。但我想我不知道搜索该帖子的正确术语。我想知道我是否应该将我的问题留给可能会以我的方式表达他们的问题的其他人......?

标签: javascript node.js express


【解决方案1】:

您可以利用闭包和立即调用函数来代替 async.forEach:

// get all elements from redis
function getAll(emergIP, callback) {
  redis.hgetall(emergIP, function (err, data) {
    if (err) {
      return callback(err);
    }

    console.log('emergIP inside the call: ' + emergIP);
    if (data) {
      var temp = emergIP.split(":");
      var key = temp[1];
      console.log('the key is: ' + key);
    }

    return callback(null, data);
  });
}

// Iterate all over the results
function getResults (reply, callback) {
  var retdata = [];
  console.log('length is: ' + reply.length);
  var length = reply.length;

  if (!length) {
    return callback(null, retdata);
  }

  for (var i = 0; i < length; i++) {
    var emergIP = [i];
    console.log('emergIP outside the call: ' + emergIP);

    (function (emergIP, i) {
      getAll(emergIP, function (err, data) {
        if (err) {
          // @todo: how would you like to handle the error?
        }

        retdata.push({key:data.callerid});

        if (i === length - 1) {
          return callback(null, retdata);
        }
      });
    }(emergIP, i));
  } //end for loop
}

router.get('/', function (req, res, next) {
  redis.send_command("SCAN", [0, "MATCH", "emergency:*"], function (err, reply) {
    if (reply) {
      getResults(reply[1], function (err, data) {
        if (err) {
          // @todo: how would you like to handle this in case of error?
        }

        res.send(JSON.stringify(data));
      });
    } //end if
    else {
      //no emergency data defined yet
      var retval = { "res": false, "msg": "no emergency data defined" };
      res.send(JSON.stringify(retval));

    }
  }); //end send_command
});

编辑

我对代码进行了一些修改,以便在迭代完成时返回 json。这不是完美的代码,因为在这种情况下,如果没有要迭代的结果,它根本不会向客户端返回响应。考虑使用 async.each:http://caolan.github.io/async/docs.html#.each

EDIT2

我尝试将代码解耦并将其拆分为函数。您可以将这些函数移动到另一个文件中,然后将它们引入路由器。抱歉,如果有任何错误导致代码无法正常运行,我实际上并没有尝试运行它。

【讨论】:

  • 这非常有效。我将研究节点闭包和立即调用的函数以供将来参考。非常感谢
  • 唯一的其他相关问题是我应该如何/在哪里通过响应对象返回此数据以显示在网页上?我尝试取消注释 retdata.push() 方法,但它不起作用
  • 当然,它不会起作用,因为请记住在 for 迭代中您正在执行异步代码 :) 因此,您的代码将向客户端发送回响应 res.send(JSON.stringify(retdata)); 而无需等待 redis .hgetall 完成。我稍后会发布一个解决方案作为另一个答案。
  • @Happydevdays 刚刚修改了上面的答案,大家可以看看。
  • 谢谢。所以听起来您建议最好的解决方案是使用 async.each 而不是您发布的解决方案?
猜你喜欢
  • 2023-01-19
  • 2020-12-16
  • 2020-10-22
  • 1970-01-01
  • 2015-08-24
  • 1970-01-01
  • 2019-04-20
  • 2019-04-01
  • 2017-07-04
相关资源
最近更新 更多