节点行为

Nodejs behaviour

我一直在做nodeJS+MongoDB,用了几个月的Express和Mongoose框架,想请教各位,遇到下面这样的情况到底是怎么回事:

Model1.find({}, function (err, elems) {
    if (err) {
        console.log('ERROR');
    } else {
        elems.forEach(function (el) {
            Model2.find({[QUERY RELATED WITH FIELDS IN 'el']}, function (err, elems2) {
                if (err) {
                    console.log('ERROR');
                } else {
                    //DO STAFF.
                }
            });
        });
    }
});

我最好的猜测是有一个主线程在 elems 上循环,然后不同的线程参与 Model2 上的每个查询,但我不太确定。

对吗?而且,这是一个好的解决方案吗?如果不是,在这种情况下,您将如何编码,您需要从 Model1 获取的每个元素中的信息以从 Model2 获取元素,并执行您正在寻找的实际功能?

我知道我可以详细说明一个更复杂的查询,在那里我可以获得 elems 中每个 'el' 的所有元素,但我宁愿不这样做,因为那样的话我会担心内存开销。

此外,我一直在考虑更改数据模型,但我已经仔细研究过了,我相信这是经过深思熟虑的,但我认为这不是我的应用程序的最佳解决方案。

谢谢!

NodeJS 是一个单线程环境,它异步工作以阻止函数调用,例如您的情况下的网络请求。所以只有一个线程,你的查询结果将被异步调用,这样就不会因为密集的网络操作而阻塞任何东西。

在您的场景中,如果第一个查询 returns 相当多的记录,例如 100000 千条,您可能会在循环中耗尽 mongo 服务器,因为您将查询与结果一样多的服务器立即查询。这是因为节点在异步工作时不会停止接收每个查询的结果。

因此通常手动限制对网络操作的请求是一个很好的做法。在异步环境中工作时,这不是微不足道的。一种方法是使用递归函数调用。基本上,您将任务分成几组,然后分批完成每组,一旦完成了一批,您就可以开始下一组。

这里有一个简单的例子说明如何做,我使用了 promises 而不是回调函数,Q 是一个对处理 promises 非常有用的 promise 库:

var rows = [...]; // array of many

function handleRecursively(startIndex, batchSize){
 var promises = [];
 for(i = 0; i < batchSize && i + batchSize < rows.length; i++){
   var theRow = rows[startIndex + i];
   promises.push(doAsynchronousJobWithTheRow(theRow));
 }
 //you wait until you handle all tasks in this iteration
 Q.all(promises).then(function(){
   startIndex += batchSize;
   if(startIndex < rows.length){ // if there is still task to do continue with next batch
handleRecursively(startIndex, batchSize);    }
 })
}

handleRecursively(0, 1000);

这是最佳解决方案:

Model1.find({}, function (err, elems) {
    if (err) {
        console.log('ERROR');
    } else {
        loopAllElements(0,elems);
    }
});
function loopAllElements(startIndex,elems){
    if (startIndex==elems.length) {
        return "success"; 
    }else{
            Model2.find({[QUERY RELATED WITH FIELDS IN elems[startIndex] ]}, function (err, elems2) {
                if (err) {
                    console.log('ERROR');
                    return "error"; 
                } else {
                    //DO STAFF.
                    loopAllElements(startIndex+1, elems);  
                }
            });
    }
}