Node.js 和文件系统:这是竞争条件吗?
我在类中有以下代码。 (它是coffescript——它用于couchdb实用程序!——但这实际上是一个node.js问题)。我正在尝试使用 Node 0.49 以 Node Way 的方式进行操作,这意味着对文件系统操作使用异步调用。起初,我很抓狂,因为在处理过程中 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()
立即返回,所以它会争先恐后地向函数调用提供数组中的下一个文件名?或者我对给定范围内价值观的持久性有一些误解?
I have the following code inside a class. (It's coffeescript-- and it's for a couchdb utility!-- but this is really a node.js question). I'm attempting to do things The Node Way, using Node 0.49, and that means using asynchronous calls for filesystem operations. At first, I was pulling my hair out because this.sentinel
went to zero several times during the course of processing, so I know I'm doing something wrong there. But then I hit an even weirder issue: down in load_directory, see those console.log()
calls? Watch when happens when I run this.
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()
Here's what I get:
X1: memberByName.js
X1: memberByClub.js
X2: memberByClub.js
X2: memberByClub.js
This is surreal, and it looks a lot like a race condition. "memberByName" gets passed to fs.stat()
, which in turn passes "memberByClub" to load_file()
, implying... what? That because load_file()
returned immediately, it raced around and presented the next file name in the array to the function call? Or do I have some misunderstanding about the persistence of values in a given scope?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不,你所看到的是预期的。您必须记住的一件事是 fs.stat 是异步的。因此,外部循环(
for fname in files
)将在调用fs.stat
的任何回调之前完成循环。您看到
memberByClub.js
两次的原因是您在日志记录语句中使用fname
,但该变量来自闭包,在回调时该变量已更改调用fs.stat
。您可以使用
do (fname) =>
包装内部循环以获得正确的日志记录语句,但我认为您需要重新构造代码以实现您想要对整个类执行的操作。No, what you see is expected. One thing you have to remember is that
fs.stat
is asynchronous. So, the outer loop (for fname in files
) will finish looping before any of the callbacks tofs.stat
is called.The reason why you see
memberByClub.js
twice is that you are usingfname
in the logging statement, but that variable is from the closure, which has changed by the time your callback tofs.stat
is called.You can wrap the inner loop with
do (fname) =>
to get the correct logging statements, but I think you need to restructure your code to achieve what you are trying to do with the whole class.