6

我有以下代码:

// Retrieve
var MongoClient = require("mongodb").MongoClient;
var accounts = null;
var characters = null;

// Connect to the db
MongoClient.connect("mongodb://localhost:27017/bq", function(err, db) {
   if(err) { return console.dir(err); }

    db.createCollection('accounts', function(err, collection) {
        if(err) { return console.dir(err); }
        else { accounts = collection; }

        createAccount("bob","bob");
        createAccount("bob","bob");
        createAccount("bob","bob");
        createAccount("bob","bob");
    });
});


function createAccount(email, password)
{
    accounts.findOne({"email":email}, function(err, item) {
        if(err) { console.dir(err); }
        else {
            if(item === null) {
                accounts.insert({"email":email, "password":password}, function(err, result) {
                    if(err) { console.dir(err); }
                    else { console.dir("Account " + email + " created."); }
                });
            }
            else {
                console.dir("Account already exists.")
            }

        }
    });
}

当我第一次运行脚本时,我最终得到了 bob 的 4 个帐户。当我第二次运行它时,我收到 4 条帐户已经存在的消息。

我很确定我知道为什么会这样,我想出的解决方案是使用某种队列来处理数据库的每次读/写。我想知道的是,这是否是正确的方法,一般的最佳实践是什么?

4

3 回答 3

10

一些语言提供了一种特殊的语言结构来处理这个问题。例如,C# 有async/await关键字,让您可以像调用同步 API 一样编写代码。

JavaScript 没有,您必须将createAccount调用与回调链接起来。

有些人开发了可以帮助您组织此代码的库。例如asyncstepnode-promiseQ

您还可以使用程库,这是一个使用纤程/协程扩展 JavaScript 运行时的本机库。

有些人用类似于async/的结构扩展了语言awaitstreamline.jsIcedCoffeeScriptwind.js。例如,streamline.js(我是作者,所以我显然有偏见)_用作特殊的回调占位符,并让您将示例编写为:

var db = MongoClient.connect("mongodb://localhost:27017/bq", _):
var accounts = db.createCollection('accounts', _);
createAccount("bob","bob", _);
createAccount("bob","bob", _);
createAccount("bob","bob", _);
createAccount("bob","bob", _);

function createAccount(email, password, _) {
    var item = accounts.findOne({"email":email}, _);
    if (item === null) {
        accounts.insert({"email":email, "password":password}, _);
        console.log("Account " + email + " created."); }
    } else {
        console.log("Account already exists.")
    }
}

And, last but not least, new language features such as generators and deferred functions are being discussed for future versions of JavaScript (generators are very likely to land in ES6, deferred functions seem to be a bit stalled).

So you have many options:

  • stick to callbacks
  • use a helper library
  • use the fibers runtime extension
  • use a language extension
  • wait for ES6
于 2013-02-08T22:42:30.697 回答
0

在电子邮件上添加唯一约束,您将不必再检查用户是否存在!

于 2013-02-08T05:39:46.597 回答
-1

JavaScript 是异步的。accounts.findOne立即返回,所以基本上你所有的 4 条语句都会一起执行。

什么accounts.findOne是,它说找到一个{"email":email},当你找到它时,运行第二个参数中的函数。然后它返回函数并继续下一个 CreateAccount 语句。同时,当从硬盘返回结果时(这比执行这些语句花费的时间要长得多),它进入函数,并且由于没有用户,所以它添加了一个。说得通?

更新这是在 JavaScript 中执行此操作的正确方法。

MongoClient.connect("mongodb://localhost:27017/bq", function(err, db) {
   if(err) { return console.dir(err); }

    db.createCollection('accounts', function(err, collection) {
        if(err) { return console.dir(err); }
        else { accounts = collection; }

        createAccount("bob","bob", function() {
            createAccount("bob","bob", function() {
                createAccount("bob","bob", function() {
                    createAccount("bob","bob", function() {
                     });
                });
            });
        });
    });
});


function createAccount(email, password, fn)
{
    accounts.findOne({"email":email}, function(err, item) {
        if(err) { console.dir(err); }
        else {
            if(item === null) {
                accounts.insert({"email":email, "password":password}, function(err, result) {
                    if(err) { console.dir(err); }
                    else { console.dir("Account " + email + " created."); }
                    fn();
                });
            }
            else {
                console.dir("Account already exists.")
                fn();
            }

        }
    });
}
于 2013-02-08T02:56:58.443 回答