2011-07-10 38 views
6

我在類裏面有下面的代碼。 (這是coffeescript--它是一個couchdb實用程序! - 但這實際上是一個node.js問題)。我試圖使用節點0.49來完成節點方式的事情,這意味着使用異步調用進行文件系統操作。起初,因爲this.sentinel在處理過程中幾次歸零,所以我知道自己在那裏做錯了什麼。但後來我碰到一個更奇怪的問題:在load_directory下,看到那些console.log()調用?當我運行這個時,觀察何時發生。Node.js和文件系統:這是一個競爭條件?

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()立即返回,它跑來跑去,並將數組中的下一個文件名稱呈現給函數調用?或者,我是否對給定範圍內的值的持續存在誤解?

回答

8

不,您看到的是預期的。有一點你必須記住的是fs.stat是異步的。因此,在調用任何回調到fs.stat之前,外部循環(for fname in files)將結束循環。

你之所以看到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() 
+0

謝謝。它*是我誤解了範圍和異步的相互作用。有趣的是,我在多年的客戶端編程中從來沒有打過類似的東西。我可以把'do'操作符添加到我的coffeescript arsenal中。 –