Node.js和Filesystem:这是竞争条件吗?

时间:2011-07-10 17:03:59

标签: node.js coffeescript

我在类中有以下代码。 (这是coffeescript--它是一个couchdb实用程序! - 但这确实是一个node.js问题)。我正在尝试使用Node 0.49做Node Node,这意味着使用异步调用来进行文件系统操作。起初,我正在拔头发,因为this.sentinel在处理过程中几次变为零,所以我知道我在那里做错了。但后来我遇到了一个更奇怪的问题:在load_directory中,请看那些console.log()来电?当我运行时,请注意何时发生。

check_sentinel: ->
    @sentinel--
    if @sentinel == 0
        @emit('designDirLoaded', @object)

load_file: (rootdir, filename, object) ->
    @sentinel++
    fname = path.join(rootdir, filename)
    @manifest.push(fname)
    fs.readFile fname, (err, data) =>
        object[filename] = data
        @check_sentinel()

load_directory: (dirpath, object) ->
    @sentinel++
    fs.readdir dirpath, (err, files) =>
        for fname in files
            console.log("X1: ", fname)
            fs.stat path.join(dirpath, fname), (err, stats) =>
                console.log("X2: ", fname)
                if stats.isFile()
                    @load_file(dirpath, fname, object)
                if stats.isDirectory()
                    object[fname] = {}
                    @load_directory(path.join(dirpath, fname), object[fname])
        @check_sentinel()

这是我得到的:

X1:  memberByName.js
X1:  memberByClub.js
X2:  memberByClub.js
X2:  memberByClub.js

这是超现实主义,看起来很像竞争条件。 “memberByName”传递给fs.stat(),后者又将“memberByClub”传递给load_file(),暗示......什么?那是因为load_file()立即返回,它在数组中运行并向函数调用提供了下一个文件名?或者我对给定范围内的值的持久性有一些误解?

1 个答案:

答案 0 :(得分:8)

不,你看到的是预期的。您必须记住的一件事是fs.stat是异步的。因此,外部循环(for fname in files)将在调用fs.stat的任何回调之前完成循环。

您看到memberByClub.js两次的原因是您在日志记录语句中使用fname,但该变量来自闭包,该回调在回调到{{1}时已更改被称为。

您可以使用fs.stat包装内部循环以获取正确的日志记录语句,但我认为您需要重新构建代码以实现您尝试对整个类进行的操作。

do (fname) =>