【问题标题】:Node.js and the Filesystem: is this a race condition?Node.js 和文件系统:这是竞争条件吗?
【发布时间】:2011-10-02 07:40:24
【问题描述】:

我在一个类中有以下代码。 (它是咖啡脚本——它是用于 couchdb 实用程序的!——但这确实是一个 node.js 问题)。我正在尝试使用 Node 0.49 以 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() 立即返回,它跑来跑去并将数组中的下一个文件名提供给函数调用?还是我对给定范围内的值的持久性有一些误解?

【问题讨论】:

    标签: node.js coffeescript


    【解决方案1】:

    不,你看到的是预期的。您必须记住的一件事是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()
    

    【讨论】:

    • 谢谢。 我误解了作用域和异步的交互。有趣的是,在多年的客户端编程中,我从未遇到过这样的事情。我可以将 do 运算符添加到我的咖啡脚本库中。
    猜你喜欢
    • 2017-09-17
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 2014-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多