【问题标题】:Node.js - Async Whilst loop not iteratingNode.js - 异步而循环不迭代
【发布时间】:2013-08-04 05:36:36
【问题描述】:

根据上一个问题 Illegal break statement (Node.js) 的建议,我实现了 async.whilst(),但它不会重复多次。

我正在尝试通过在 ID 末尾增加一个数字并查询 Mongo 以查看该 ID 是否存在来查找唯一 ID。如果不存在,则找到唯一 ID。它只循环一次,而不是直到找到唯一的。怎么了?

代码:

 var uniqueNumber = 1;
 var newUnique;

 async.whilst(
    function () { 

       var uniqueNum_string = uniqueNumber.toString(); 
       newUnique = data.id + uniqueNum_string;

       db.collection('landmarks').findOne({'id':newUnique}, function(err, data){

           if (data){
              console.log('entry found!');
              return;
           }

           else {
              console.log('entry not found!');

           }
        });

  },
  function (callback) {

     uniqueNumber++;

   },
   function (err) {

      saveLandmark(newUnique);
   }
);

【问题讨论】:

  • 我相信你必须在 "entry not found" else 语句中返回 true 才能再次循环。
  • 你不能真正使用while,因为测试功能应该是同步的。您还必须在迭代器中实际调用回调。
  • 好点@AndreasHultgren。我完全忽略了这一点。
  • 那么应该如何迭代呢? @AndreasHultgren
  • @jrbaldwinn 等一下我会发布答案

标签: javascript node.js asynchronous node-async


【解决方案1】:

我实际上找不到适合这个任务的好的异步函数,所以我使用 async.forever() 一起破解了一些东西。该函数将一直运行,直到您回调“错误”,这是您想要做的。

var uniqueNumber = 1;
var newUnique;

async.forever(function (next) {
  var uniqueNum_string = uniqueNumber.toString(); 
  newUnique = data.id + uniqueNum_string;

  db.collection('landmarks').findOne({'id':newUnique}, function(err, data){
    if (data){
      console.log('entry found!');
      uniqueNumber++;
      next();
    }

    else {
      console.log('entry not found!');
      next('unique!'); // This is where the looping is stopped
    }
  });
},
function () {
  saveLandmark(newUnique);
});

关于您要解决的问题,在我看来,您想插入一个具有唯一 ID 的新文档。如果是这种情况并且你会经常这样做,我会说这是一种非常低效的方法。如果您在数据库中有一千个文档,您甚至会在接近唯一 ID 之前对数据库执行一千个完全无意义的请求。

更好的方法是从集合中获取按 id 降序排序的第一个文档(例如,最高的 id)。然后将该 id 加一并尝试插入,直到它不被拒绝。因为即使您找到唯一的 id,在您保存文档时,可能已经从另一个客户端或另一个实例进行了另一个插入(在负载平衡的情况下)。在您的情况下,这可能是问题,也可能不是问题,我对您的应用了解不够,我只是认为您应该了解当前方法和我的回答的缺点。

【讨论】:

  • 有效!我实际上是在尝试根据用户提交的文档的名称生成唯一的 URL。我正在使用您的 monguurl 插件,但由于某种原因它无法正常工作(过去曾使用过)。无论如何,系统中不应该有太多重复我需要的东西......谢谢!
  • 酷,如果你使用 mongoose,我会建议 monguurl...如果你认为我的模块有问题,请在 github 上创建一个问题 :) 我现在看到一个神秘的 data.id我考虑了一下,所以我想我的警告毕竟不需要,这正是我所做的(除了我插入而不是查找,你可能会或可能不会遇到问题,这取决于它是否有可能两个客户端同时尝试插入一个文档)。
【解决方案2】:

像这样的东西?我没有测试它,因为我不知道你使用的是什么数据库模块,但逻辑应该是显而易见的。

function searchNubmersForResults(firstNumber, callback) { 
    //place other variables here, and you can collect the results within the closure, and send them as arguments to your callback
   function testNumber(uniqueNumber) {
        var uniqueNum_string = uniqueNumber.toString(); 
        newUnique = data.id + uniqueNum_string;

        db.collection('landmarks').findOne({'id':newUnique}, function(err, data){

            if (data){
                console.log('entry found!');
                callback(data);//We're done, use the callback on the data
            } else {
                console.log('entry not found!');
                testNumber(uniqueNumber++);//Launch the next test
            }
        });
    }

    testNumber(firstNumber);//Laucn the first test
}

searchNubmersForResults(0, function(data) {
    console.log('You have data now: ' + data);
});

【讨论】:

    猜你喜欢
    • 2014-07-04
    • 1970-01-01
    • 1970-01-01
    • 2016-07-10
    • 2015-04-11
    • 1970-01-01
    • 2016-06-17
    • 2015-02-27
    • 2017-06-16
    相关资源
    最近更新 更多