Javascript 如何绕过MongoDB/节点异步问题?
我有以下代码:Javascript 如何绕过MongoDB/节点异步问题?,javascript,node.js,mongodb,asynchronous,Javascript,Node.js,Mongodb,Asynchronous,我有以下代码: // 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); }
// 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条消息,表明该帐户已经存在
我很确定我知道这是为什么,我提出的解决方案是使用某种队列来处理数据库的每次读/写,每次一个。我想知道的是,这是否是正确的方法,一般的最佳实践是什么?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();
}
}
});
}
在电子邮件上添加一个唯一的约束,您将不必再检查用户是否存在 一些语言提供了一种特殊的语言结构来处理这个问题。例如,C#有
async
/await
关键字,让您编写代码时就像调用同步API一样
JavaScript没有,您必须用回调链接createAccount
调用
有些人开发了一些库,可以帮助您组织这些代码。例如
您还可以使用该库,它是一个本机库,通过光纤/协同路由扩展JavaScript运行时
有些人用类似于async
/await
:,或。例如,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.")
}
}
最后但并非最不重要的一点是,诸如和等新的语言特性正在为未来的JavaScript版本进行讨论(生成器很可能在ES6中实现,延迟函数似乎有点停滞)
所以你有很多选择:
- 坚持回调
- 使用辅助程序库
- 使用光纤运行时扩展
- 使用语言扩展名
- 等待ES6
电子邮件
上添加一个唯一索引,然后处理插入
错误,如果该帐户已经存在,则会出现重复
error。这听起来是一个很好的处理方法。您也可以尝试用承诺来解决问题,请参阅:我理解为什么会发生这种情况,我想知道的是最好的解决方法是什么。我添加了上面的代码,以展示用JavaScript做这件事的正确方法。或者,您可以使用步骤库,我倾向于否决这个基于更新的答案,该更新说:“这是在Javascript中这样做的正确方法”。首先,关于Node.js中的异步使用,而不是Javascript,很少有一种“正确”的方法在代码中执行任何操作。希望任何rational开发人员都能认识到,这种场景中的嵌套回调不会扩展,并且不是理想的解决方案。我同意这句话:“然而,多层次的嵌套应该是一种代码味道——是时候想想你可以把什么抽象成单独的、小的模块了。”通过另一个值得一提的选项是,它是由与IcedOfficeScript相同的开发人员开发的——实际上,它是在纯JS中工作的原始版本。但由于某些原因,它生成的代码是streamline.js的两倍(尽管函数数量大致相同),因此我建议使用streamline.js。此外,streamline.js可以让您通过try/catch更自然地处理错误,并且有一个fibers选项可以加快处理速度。另外值得注意的是,streamline.js也可以与CoffeeScript一起使用(通过在CoffeeScript转换后应用streamline.js转换;文档中有更多详细信息)。