如何在循环结束后在javascript中执行语句?

时间:2016-04-18 20:52:57

标签: javascript node.js mongodb mongodb-query

我正在查询mongo数据库,以便在胭脂游戏中检索显示的图块。这是我使用的功能:

function get_display(){
    var collections = ['austinsroom'];
    var db  = mongojs(uri, collections);
    var temphtml = '';

    for(var j = 0; j < 3; j++) {
        console.log("y=" + String(j));
        db.austinsroom.find({"y": j}, {}).sort({"x": 1}, function(err, records) {
            if(err) {
                console.log("There was an error executing the database query.");
                return;
            } 
            var i = records.length;
            while(i--) {
                temphtml += records[i].display;
            }   
            temphtml += '<br>';
            //console.log(temphtml);
            //return temphtml;
            //THE ONLY WAY I CAN GET ANYTHING TO PRINT IN THE CONSOLE IS IF I PUT IT INSIDE THE LOOP HERE
            });
        //console.log(temphtml);
        //return temphtml;
        //THIS DOES NOTHING
    }
    //console.log(temphtml);
    //return temphtml;
    //THIS DOES NOTHING
}
get_display();

如果我把console.log(temphtml)放在循环中,它会打印三次,这不是我想要的。我只想要最后一个字符串(即...<br>...<br>...<br>。我也不能最终返回temphtml字符串,这实际上是重要的事情。这是javascript的一些怪癖吗?为什么它不会在执行之后执行语句循环?

另外:有没有更好的方法来检索存储在mongo数据库中的网格的每个元素,以便它可以正确显示?这是mongo文档的样子:

{
    "_id": {"$oid": "570a8ab0e4b050965a586957"},
    "x": 0,
    "y": 0,
    "display": "."
}

现在,游戏应该使用坐标的x和y值在所有空白区域显示“.”。数据库由“x”值索引。

2 个答案:

答案 0 :(得分:5)

async.whilst。您需要for循环的流控制,为此提供回调来控制每个循环迭代。

var temphtml = "",
    j = 0;

async.whilst(
  function() { return j < 3 },
  function(callback) {
    db.austinsroom.find({"y": j }, {}).sort({"x": 1}, function(err, records) 
      temphtml += records.map(function(el) {
          return el.display;
      }).join("") + '<br>';
      j++;
      callback(err);
    });
  },
  function(err) {
     if (err) throw err;
     console.log(temphtml);
  }
)

或者使用Promise.all()收集的承诺返回“一个大的结果”。但是你还需要从mongojs切换到promised-mongo,作为最接近的等价物,因为有更多的mongodb驱动程序实际上支持promises。那个只是来自mongojs的直接分支:

var temphtml = "",
    j = 0,
    promises = [];

for ( var j=0; j < 3; j++ ) {
   promises.push(db.austinsroom.find({"y": j }, {}).sort({"x": 1}).toArray());
   promises.push('<br>');   // this will just join in the output
)

Promise.all(promises).then(function(records) {
    temphtml += records.map(function(el) {
        return el.display;
    }).join("");
})

不完全相同,因为它是一个列表输出而不是三个,但重点是Promise个对象延迟直到实际调用解析,因此您可以在循环中提供参数,但稍后执行

答案 1 :(得分:0)

我不使用MongoDB,但从我正在阅读的内容中它是异步的。所以发生的事情是你的db.austinsroom.find调用触发另一个“线程”并返回for循环以继续下一次迭代。

执行所需操作的一种方法是检查db.austinsroom.find函数的末尾,看看是否已完成for循环。类似的东西:

function get_display()
{
    var collections = ['austinsroom'];
    var db  = mongojs(uri, collections);
    var temphtml = '';
    var doneCounter = 0;

    for(var j = 0; j < 3; j++)
    {
        console.log("y = " + String(j));
        db.austinsroom.find({"y": j}, {}).sort({"x": 1}, function(err, records)
        {
            if(err)
            {
                console.log("There was an error executing the database query.");
                return;
            } 
            var i = records.length;
            while(i--)
            {
                temphtml += records[i].display;
            }   
            temphtml += '<br>';

            // we're done with this find so add to the done counter
            doneCounter++;

            // at the end, check if the for loop is done
            if(doneCounter == 3)
            {
                // done with all three DB calls
                console.log(temphtml);
            }
       });
    }
}

这可能不是最好的方式,因为我对MongoDB一无所知,但它应该让你走上正确的道路。