2011-07-10 9 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

いいえ、表示されている内容が必要です。覚えておかなければならないことの1つは、fs.statが非同期であることです。したがって、外部ループ(for fname in files)は、fs.statへのコールバックのいずれかが呼び出される前にループを終了します。あなたが二回memberByClub.jsを参照してください理由

理由は、loggingステートメントで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

ありがとうございます。スコープと非同期の相互作用を誤解していました。面白いことに、何年ものクライアント側のプログラミングでこれほどのものを打ちましたことはありません。そして私は私のcoffeescript arsenalに 'do'演算子を追加します。 –

関連する問題