2016-04-01 5 views
1

RxJsとnode.jsを使用してディレクトリツリーを走査しようとしています。RxJsを使用してnode.js内のディレクトリツリーを走査する

私が働いて解決策を考え出した:非同期操作を使用して.mapへのより効率的な/簡潔な方法はあり

  1. const filesInDir = Rx.Observable.fromNodeCallback(fs.readdir) 
    const statFile = Rx.Observable.fromNodeCallback(fs.stat) 
    
    const listFiles = (prefix, dir = '') => { 
        const file$ = filesInDir(`${prefix}/${dir}`) 
         .flatMap(file => file) 
         .filter(file => !file.startsWith('.')) 
        const isDir$ = file$ 
         .map(file => statFile(`${prefix}/${dir}/${file}`)) 
         .flatMap(file => file) 
         .map(file => file.isDirectory()) 
        return file$ 
         .zip(isDir$, (file, isDir) => {return {file, isDir}}) 
         .map(f => { 
          if (f.isDir) { 
           return listFiles(prefix, `${dir}/${f.file}`) 
          } 
          return Rx.Observable.return(`${dir}/${f.file}`) 
         }) 
         .flatMap(file => file) 
    } 
    
    listFiles('public') 
        .toArray() 
        .subscribe(list => { 
         console.log(list) 
        }) 
    

    質問?

答えて

2

.zip部分について同じ質問グレート質問。

このクエリを最適化するには、いくつかのことができると思います。

最初にmapオペアータを変更してから.flatMap(file => file)を1つのフラットマップに変更することができます。小さな改善ですが、コードは少なくて済みます。

const file$ = filesInDir(`${prefix}/${dir}`) 
    .flatMap(file => file) 
    .filter(file => !file.startsWith('.')) 
const isDir$ = file$ 
    .flatMap(file => statFile(`${prefix}/${dir}/${file}`)) 
    .map(file => file.isDirectory()) 
return file$ 
    .zip(isDir$, (file, isDir) => {return {file, isDir}}) 
    .flatMap(f => { 
     if (f.isDir) { 
      return listFiles(prefix, `${dir}/${f.file}`) 
     } 
     return Rx.Observable.return(`${dir}/${f.file}`) 
    }) 

主な改善点は、実際にファイルシステムに2回ぶつかると思います。 観測可能なシーケンスは、ホット/キャッシュされたシーケンスではありません。filesInDir この場合、ディレクトリツリーの再帰的なウォークは機能しません。 これを念頭に置いて、すべてのファイルを取得するために一度呼び出すと、isDirectoryのチェックを行うために再度呼び出しています。 これは潜在的なパフォーマンスコストとバグの両方をもたらします。 ディスクをヒットした場合、返されるファイルの順序は常に同じ順序になると想定しています。 1秒間無視しても、そのディスクは変更可能であり、に変更される可能性があります。 非同期の世界では、シーケンスが同じ順序で返されることが保証されます。 私のマシン(Windows 10)では、シーケンスはほとんど同じ順序で返されます。 しかし、十分な深さのツリー(例:_C:_)では、毎回不一致が発生しました。

とにかく、パフォーマンスの修正はバグ修正です。 毎回ファイルシステムから再読み込みする代わりに、一度だけ実行できます。 はまた、我々はもはや二つの配列で動作するようにしようとしているので、これはまたZip句を除去する利点を持っていないstatFile

const listFiles = (prefix, dir) => { 
    return file$ = filesInDir(`${prefix}/${dir}`) 
     .flatMap(file => file) 
     .filter(file => !file.startsWith('.')) 
     .flatMap(file => statFile(`${prefix}/${dir}/${file}`) 
        .map(sf => {return {file, isDir: sf.isDirectory()}})) 
     .flatMap(f => { 
      if (f.isDir) { 
       return listFiles(prefix, `${dir}/${f.file}`) 
      } 
      return Rx.Observable.return(`${dir}/${f.file}`) 
     }) 
} 

に渡されたファイルの閉鎖に結果をマップflatMapstatFile()コールを移動します。

関連する問題