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

Elf*_*erg 6 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()
Run Code Online (Sandbox Code Playgroud)

这是我得到的:

X1:  memberByName.js
X1:  memberByClub.js
X2:  memberByClub.js
X2:  memberByClub.js
Run Code Online (Sandbox Code Playgroud)

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

Bar*_*Rho 8

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

你看memberByClub.js两次的原因是你fname在日志记录语句中使用,但是该变量来自闭包,它在调用回调时已经改变fs.stat.

你可以用内循环使用do (fname) =>,以获得正确的日志语句,但我认为你需要调整你的代码来实现你正在试图与全班做.

load_directory: (dirpath, object) ->
    @sentinel++
    fs.readdir dirpath, (err, files) =>
        for fname in files
            do (fname) =>
                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()
Run Code Online (Sandbox Code Playgroud)