【问题标题】:How to ensure that a statement gets executed after a loop completes?如何确保循环完成后执行语句?
【发布时间】:2012-12-04 03:43:52
【问题描述】:

下面是我在 routes/index.js 中的代码快照

exports.index = function(req, res){
    var results=new Array();
    for(var i=0; i<1000;i++){
        //do database query or time intensive task here based on i 
        // add each result to the results array
    }
    res.render('index', { title: 'Home !' , results:results });
};

如果我运行这段代码,由于 javascript 的异步特性,最后一行在循环被完全处理之前被执行。因此我的网页没有结果。我如何构建这种方式,以便在查询完成后加载页面?


更新

在循环内我有如下数据库代码 (Redis) -

client.hgetall("game:" +i, function(err, reply) {

           results.push(reply.name);
        });

【问题讨论】:

  • 循环体中到底是什么?是否支持回调?
  • 嗨 zerkms - 我刚刚更新了问题以添加有关该部分的详细信息。是的,它支持回调。

标签: javascript node.js asynchronous express


【解决方案1】:

使用async library

exports.index = function(req, res){
    var results=new Array();
    async.forEach(someArray, function(item, callback){
        // call this callback when any asynchronous processing is done and
        // this iteration of the loop can be considered complete
        callback();
    // function to run after loop has completed
    }, function(err) {
        if ( !err) res.render('index', { title: 'Home !' , results:results });
    });
};

如果循环内的任务之一是异步的,则需要向异步任务传递一个调用callback() 的回调。如果您没有要在 forEach 中使用的数组,只需使用 1-1000 的整数填充一个即可。

编辑:给定您的最新代码,只需将async callback() 放在responses.push(reply.name) 之后即可。

【讨论】:

  • 我看不出你的第二个版本比 OP 的原版好多少。第一个很好,但要确保在将结果添加到结果数组之后调用callback,而不仅仅是在循环体的末尾。
  • 是的,请参阅关于将 i 增量传递给回调的已编辑答案。
  • 查看我关于递增 i 并通过回调任何异步处理之后进行条件检查的注释。
  • 在您的第二个示例中,某些项目将运行多次。一个非异步的 for 循环是行不通的。
【解决方案2】:
exports.index = function(req, res) {
  var events = require("events");
  var e = new events.EventEmitter();
  e.expected = 1000;
  e.finished = 0;
  e.results = [];

  e.on("finishedQuery", (function(err, r) {
    this.finished += 1;
    this.results.push(r && r.name);
    if (this.finished === this.expected) {
       res.render('index', { title: 'Home !' , results:this.results });
    };
  }).bind(e));

  for (var i = 0; i < e.expected; i++) {
    client.hgetall("game:" + i, function(err, reply) {
      e.emit("finishedQuery", err, reply);
    });
  };
};

当然,上面的代码不能处理 [1 个或多个] 错误。您需要添加仅响应 (1) 第一个错误或 (2) 如果没有发生错误的逻辑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-14
    • 1970-01-01
    • 2020-10-27
    • 2020-11-21
    • 1970-01-01
    • 1970-01-01
    • 2016-09-02
    • 2021-02-28
    相关资源
    最近更新 更多