如何解决这个MongoDB/Node异步问题?

use*_*584 6 javascript asynchronous mongodb node.js

我有以下代码:

// 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.")
            }

        }
    });
}
Run Code Online (Sandbox Code Playgroud)

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

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

Bru*_*ier 10

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

JavaScript没有,您必须createAccount使用回调链接调用.

有些人开发了可以帮助您组织此代码的库.例如async,step,node-promiseQ.

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

而有些人却扩展了类似于结构的语言async/ await:streamline.js,IcedCoffeeScriptwind.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.")
    }
}
Run Code Online (Sandbox Code Playgroud)

并且,最后但并非最不重要的是,新的语言功能,如生成器延迟函数正在讨论未来版本的JavaScript(生成器很可能落在ES6中,延迟函数似乎有点停滞).

所以你有很多选择:

  • 坚持回调
  • 使用帮助程序库
  • 使用光纤运行时扩展
  • 使用语言扩展名
  • 等待ES6