这个fs.readdir函数中的竞争条件在哪里?

时间:2016-12-20 11:17:19

标签: node.js race-condition fs

我想列出目录中的所有文件夹,并在结尾列表中列出有多少个文件夹。

这是我的代码:

fs.readdir(dir, (err, folders) => {
    if (err) return console.log(err);

    let count = 0;
    for (let i = 0; i < folders.length; i++) {
        let folder = folders[i];

        fs.stat(dir + '/' + folder, (err, stats) => {
            if (err) return console.log(err);

            if (stats.isDirectory()) {
                console.log(folder);
                count++;
            }
            if (i >= (folders.length - 1)) {
                console.log('folders: ' + count);
            }
        });
    }
});

代码应该:

  1. 阅读目录
  2. 为目录中的每个文件夹增加count
  3. 当目录读取完成后,请记录'folders: ' + count
  4. 在大多数情况下,这确实有效,我明白了:

    ...
    2016-12-20--09-59-12
    2016-12-20--09-59-13
    2016-12-20--09-59-14
    folders: 86
    

    有时虽然我明白了:

    ...
    2016-12-20--09-59-12
    2016-12-20--09-59-11
    2016-12-20--09-59-14
    folders: 85
    2016-12-20--09-59-13
    

    竞争条件发生在哪里?

1 个答案:

答案 0 :(得分:1)

我意识到竞争条件的发生是因为i可以在所有fs.stat完成执行之前完成递增,因为它会在fs.stats的回调之外递增。

因此我需要一个单独的变量(j)来跟踪所有fs.stats的完成情况,并且只有当那些完成递增时才能列出{{1} }}

这是正确的代码:

count

现在输出始终如一:

fs.readdir(dir, (err, folders) => {
    if (err) return console.log(err);

    let count = 0,
        j = 0; // this bad boy!

    for (let i = 0; i < folders.length; i++) {
        let folder = folders[i];

        fs.stat(dir + '/' + folder, (err, stats) => {
            if (err) return console.log(err);
            j++; // j, unlike i, only gets incremented *inside* the async function

            if (stats.isDirectory()) {
                console.log(folder);
                count++;
            }
            if (j >= folders.length) { // check j, not i
                console.log('folders: ' + count);
            }
        });
    }
});