非法的break语句(Node.js)

9
尝试在Node.js和MongoDB中查找唯一标识符,通过创建一个while循环来查询现有ID,直到找到一个唯一的值。如果该ID已经在使用中,则在末尾递增一个数字,直到Mongo返回空值。
一切都正常工作,除了当找到唯一的ID时出现的break语句。Node.js返回:SyntaxError: Illegal break statement
代码如下:
db.collection('landmarks').findOne({'id':uniqueIDer}, function(err, data){
    //if ID exists already
    if (data.id){

        var uniqueNumber = 1;

         while (1) {

            var uniqueNum_string = uniqueNumber.toString(); 
            var newUnique = data.id + uniqueNum_string;
            db.collection('landmarks').findOne({'id':newUnique}, function(err, data){

                if (data.id){
                    uniqueNumber++;
                }

                else {
                    saveLandmark(newUnique);
                    break;
                }
            });
        }
    }

    else {
        saveLandmark(uniqueIDer);
    }

});

我做错了什么?

编辑:

这是修正后的代码,如果有人需要使用异步,请查看:)

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

            if (data){
                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,'world':worldVal}, 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);
                });
            }
            else {
                saveLandmark(uniqueIDer);
            }
        });

顺便提一下:一旦您解决了语法错误,您将拥有一个锁定的应用程序。您不能在异步.findOne()中使用同步while (1)。后者需要引擎处于空闲状态才能完成,而前者永远不会让它处于空闲状态。 - Jonathan Lonowski
什么是找到唯一ID的最佳方法? - alyx
@jrbaldwinn:几乎可以确定,当您将对象添加到集合中时,每个对象都会自动分配一个唯一的ID。对象ID可能有点大且难看,但即使在群集或其他情况下,其被重复的可能性非常小。 :) - cHao
@cHao说得好。与其费尽心思创建一个独特的ID,不如直接使用MongoDB为每个文档自动创建的“_id”属性,省时省力。 - Owen
这是为了基于用户提交生成唯一URL,我希望我可以只使用_id。 - alyx
@jrbaldwinn: 你为什么不能呢?这个数字有特别的意义吗?(我猜没有,考虑到你可以轻易地选择下一个数字...) - cHao
1个回答

18

你的 break 语句不在循环体内。相反,它在一个函数体内,即 findOne 回调函数体内。为了更清楚地看到这一点,暂时使用命名函数作为回调处理程序可能会有帮助:

var cb = function(err, data){
    if (data.id){
        uniqueNumber++;
    }
    else {
        saveLandmark(newUnique);
        break;  // not inside a loop!
    }
};

db.collection('landmarks').findOne({'id':uniqueIDer}, function(err, data){
    //if ID exists already
    if (data.id){
        var uniqueNumber = 1;
        while (1) {
            var uniqueNum_string = uniqueNumber.toString(); 
            var newUnique = data.id + uniqueNum_string;
            db.collection('landmarks').findOne({'id':newUnique}, cb);
        }
    }
    else {
        saveLandmark(uniqueIDer);
    }
});

现在很明显,在回调函数体中的 break 并不在循环内部!我也通过其他方式使代码中断了,因为 uniqueNumbernewUnique 的值已经不再作用域内,但这是另一个问题。 :) 这里要注意的重要事情是,函数会在你的代码中引入一个“硬”边界,仅仅基于语言的语法可能很难看到这一点。这就是为什么这种回调式编程风格如此棘手的原因之一。

事实上,这比你最初尝试的代码要困难得多。你需要一种方法来通过可能的任意层次的回调向上传递成功信号,而你会重复调用 findOne 并分析结果(异步方式)。

你可以通过使用出色的 async 库来获得一些帮助,例如 https://github.com/caolan/async#whilst


无论如何,某种类型的异步代码都将是绝对必要的。所以 :) - cHao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接