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

How can I execute a statement AFTER a loop finishes in javascript?

本文关键字:结束 执行 语句 循环 javascript      更新时间:2023-09-26

我正在查询一个mongo数据库,以检索在rougelike游戏中显示的瓦片。这是我使用的功能:

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"值进行索引。

参见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驱动程序支持promise。这只是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对象推迟到实际调用才能解析,所以您可以在循环中提供参数,但稍后执行。

我不使用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一无所知,但它应该让你走上正确的道路。