Node.js and the file system: is this a race condition?

I have the following code inside a class. (This is coffeescript - and this is for the couchdb utility! - but it's really a node.js question). I'm trying to do something. Node Path using Node 0.49, and this means using asynchronous calls for file system operations. At first I pulled my hair out because this.sentinel changed several times to zero during processing, so I know that I am doing something wrong. But then I came across an even stranger problem: down in load_directory, see these console.log() calls? Watch when this happens, when I start it.

 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 is what I get:

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

It is surreal, and it is very similar to the state of the race. "memberByName" goes to fs.stat() , which in turn passes "memberByClub" to load_file() , implying ... what? Is it because load_file() returned immediately, it raced and represented the next file name in the array to call the function? Or do I have some misunderstanding about the preservation of values ​​in this area?

+6
source share
1 answer

No, what you see is expected. fs.stat mind that fs.stat is asynchronous. So the outer loop ( for fname in files ) will end the loop before calling any of the callbacks in fs.stat .

The reason you see memberByClub.js twice is because you use fname in the logging statement, but this variable refers to a closure that has changed by the time you call the fs.stat .

You can wrap the inner loop with do (fname) => to get the correct logging sheets, but I think you need to rebuild your code to achieve what you are trying to do with the whole class.

 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() 
+8
source

Source: https://habr.com/ru/post/892445/


All Articles