Javascript node.js异步迭代时的数据一致性

Javascript node.js异步迭代时的数据一致性,javascript,node.js,asynchronous,concurrency,couchdb,Javascript,Node.js,Asynchronous,Concurrency,Couchdb,我有一个工具,其基本思想如下: //get a bunch of couchdb databases. this is an array const jsonFile = require('jsonfile'); let dbList = getDbList(); const filePath = 'some/path/to/file'; const changesObject = {}; //iterate the db list. do asyn

我有一个工具,其基本思想如下:

//get a bunch of couchdb databases. this is an array
    const jsonFile = require('jsonfile');
    let dbList = getDbList();
    const filePath = 'some/path/to/file';
    const changesObject = {};


     //iterate the db list. do asynchronous stuff on each iteration
     dbList.forEach(function(db){
        let merchantDb = nano.use(db);

        //get some changes from the database. validate inside callback 
        merchantDb.get("_changes", function(err,changes){
          validateChanges(changes);
          changesObject['db'] = changes.someAttribute;
          //write changes to file
          jsonFile.writeFile(filePath, changesObject, function (err) {
            if (err) {
              logger.error("Unable to write to file: ");
            }
          });
    })

const validateChanges = function(changes) {
 if (!validateLogic(changes) sendAlertMail();
}
为了提高性能,迭代不是同步完成的。因此,可以“并行”运行多个迭代。我的问题是,这会导致数据不一致和/或文件写入过程中出现任何问题吗

编辑: 每次迭代都会写入相同的文件

编辑:2
这些更改存储为带有键值对的JSON对象。关键是数据库名。

如果您真的要写入一个文件,而您看起来是这样的(尽管很难确定),那么就不要;您有一个竞争条件,在此条件下,多个回调将尝试写入同一个文件,可能同时写入(请记住,除非您使用
*Sync
函数,否则不会在节点中的JavaScript线程上执行I/O操作),这充其量意味着最后一个回调获胜,最坏情况下意味着由于重叠而出现I/O错误

如果要为每个
db
写入单独的文件,那么只要
validateChanges
validateLogic
sendAlertMail
等之间没有串扰(共享状态),就可以了

只是为了细节:它将启动任务(作业),获取更改,然后将其写出来;调用
get
的回调要等到所有作业排队后才能运行

您正在循环中创建闭包,但是您这样做是可以的,这既因为您在
forEach
回调中进行闭包,也因为您在
get
回调中没有使用
db
(这对于
forEach
回调很好,但是对于其他一些可能循环数组的方式则不行)。如果您感兴趣,请参阅中有关这方面的详细信息

不过,这条线值得怀疑:

let merchantDb = nano.use('db');
我猜你的意思是(没有引用):


值得一提的是,从问题的更新和您的各种评论中可以看出,更好的解决方案是而不是每次单独写出文件。相反,您希望收集更改,然后将其写出来

您可以像这样使用经典的节点回调API:

let completed = 0;
//iterate the db list. do asynchronous stuff on each iteration
dbList.forEach(function(db) {
    let merchantDb = nano.use(db);

    //get some changes from the database. validate inside callback 
    merchantDb.get("_changes", function(err, changes) {
        if (err) {
            // Deal with the fact there was an error (don't return)
        } else {
            validateChanges(changes);
            changesObject[db] = changes.someAttribute; // <=== NOTE: This line had 'db' rather than db, I assume that was meant to be just db
        }
        if (++completed === dbList.length) {
            // All done, write changes to file
            jsonFile.writeFile(filePath, changesObject, function(err) {
                if (err) {
                    logger.error("Unable to write to file: ");
                }
            });
        }
    })
});
let completed=0;
//迭代数据库列表。在每次迭代中执行异步操作
forEach(函数(db){
设Tdb=nano.use(db);
//从数据库中获取一些更改。验证内部回调
merchantDb.get(“\u changes”),函数(err,changes){
如果(错误){
//处理发生错误的事实(不返回)
}否则{
验证变更(变更);

changesbject[db]=changes.someAttribute;//回答这个问题需要太多的猜测(我在开始回答后意识到)。什么是
jsonFile
?什么是
file
?你的真正意思是
nano.use('db')
,而不是
nano.use(db)
?感谢您的回复。是的,它应该是
nano.use(db)
。为了更好的可读性,我添加了一些导入语句。每次迭代都会写入同一个文件。@fsociety:那么不,它一点也不安全。您在单个文件上安排多个I/O操作,这可能会重叠(请记住,除非您使用
*Sync
函数,否则不会在节点中的JavaScript线程上执行I/O操作),即使它们没有重叠,也将是“最后一个赢”,因为您没有指定附加选项。从
writeFile
(其中
jsonfile.writeFile
包装):异步将数据写入文件,如果文件已经存在,则替换该文件。"每次迭代都会实现一个附加。我修改了这个问题以反映这一点。您对如何处理此处的文件写入有什么建议吗?像maybe这样的简单队列实现?@fsociety:不,知道何时完成多个异步操作并不需要使它们同步。是的,这将涉及回调函数。我不明白为什么会有问题,因为当前代码使用回调函数。事实上,有三个::-)如果您有时间限制,我肯定会避免不必要的I/O。我已经更新了答案,以显示您在这种情况下如何做到这一点。@fsocity:JavaScript语言不一定是单线程的。但是Node只运行一个JavaScript线程,所以我们不必担心上面提到的并发性,不。
let completed = 0;
//iterate the db list. do asynchronous stuff on each iteration
dbList.forEach(function(db) {
    let merchantDb = nano.use(db);

    //get some changes from the database. validate inside callback 
    merchantDb.get("_changes", function(err, changes) {
        if (err) {
            // Deal with the fact there was an error (don't return)
        } else {
            validateChanges(changes);
            changesObject[db] = changes.someAttribute; // <=== NOTE: This line had 'db' rather than db, I assume that was meant to be just db
        }
        if (++completed === dbList.length) {
            // All done, write changes to file
            jsonFile.writeFile(filePath, changesObject, function(err) {
                if (err) {
                    logger.error("Unable to write to file: ");
                }
            });
        }
    })
});