2017-05-15 9 views
1

多くの連鎖と多数の非同期操作が必要な特定のタスクでObservablesを使用する場合、フォルダ内のすべてのアイテムを一覧表示し、特定のファイルでは、各タスク(return Observable.of(folder)...)の複雑なチェーンを構築するか、バッチの終了を知らせるために最後に転送される特別な値を持つ必要があります(すべての演算子はif(res === false) return Observable.of(false)で始まります)。ReactXを使用してディレクトリ内のフォルダとファイルを一覧表示する方法

あなたの食料雑貨と、チェックアウト時にあなたの前にいる人のものの間に置いたようなもの。

すべての種類のコールバックと演算子を介して停止値を転送することを含まないより良い方法があるようです。

したがって、フォルダパス文字列を受け取り、その中のすべてのファイルとフォルダのリストを返す関数を呼び出すにはどうすればよいでしょうか。また、ファイルがHTMLファイルであるかどうか、およびフォルダにtiddlywiki.jsonというファイルが含まれているかどうかを指定します。

唯一の要件は、Observable.of(...)...のようなものを返すことができないことです。それはおそらくチェーンの一番上にある主題を持っているはずですが、それは要件ではありません。ここで

function listFolders(folder) { 
    return [ 
     { type: 'folder', name: 'folder1' }, 
     { type: 'datafolder', name: 'folder2' }, //contains "tiddlywiki.json" file 
     { type: 'folder', name: 'folder3' }, 
     { type: 'htmlfile', name: 'test.html' }, 
     { type: 'other', name: 'mytest.txt' } 
    ] 
} 
+0

あなたの質問は、広すぎます(タイトルで判断)。それは、特定のファイルのフォルダディレクトリ構造を再帰的に検索する方法の具体的な問題です。その具体的な目標に向かって質問を書き直し、詳細(入力、期待される出力)を指定することをお勧めします。あなたの質問の終わりに、より大きな目標がバッチなどであることをいつも言い表すことができます。 – user3743222

+0

[OK]を強調するために少し編集しました。 –

+0

あなたが探している機能を指定すると助けになります。その機能のインプットは何ですか?期待される成果は?あなたのアプローチはうまくいかなかったのですか?観測値を返すために使用しなければならない関数は何ですか?あなたの質問がより具体的であればあるほど、答えはより具体的になります。私が読むことから、私は 'concatMap'と再帰関数は、比較的簡単に達成しようとしていることを行う必要があることだけを伝えることができます。 – user3743222

答えて

0

は(ないものは下記を参照してください)私がレイアウトさのルールに従わないものであるが、それはガイドとして最初のものを使用して、およそ10分かかりました。

export function statFolder(subscriber, input: Observable<any>) { 
    return input.mergeMap(([folder, tag]) => { 
     return obs_readdir({ folder, tag })(folder); 
    }).mergeMap(([err, files, { folder, tag }]) => { 
     if (err) { return Observable.of({ error: err }) as any; } 
     else return Observable.from(files).mergeMap(file => { 
      return obs_stat([file,folder])(path.join(folder, file as string)); 
     }).map(statFolderEntryCB).mergeMap<any, any>((res) => { 
      let [entry, [name, folder]] = res as [any, [string, string, number, any]]; 
      if (entry.type === 'folder') 
       return obs_readdir([entry])(path.join(entry.folder, entry.name)); 
      else return Observable.of([true, entry]); 
     }, 20).map((res) => { 
      if (res[0] === true) return (res); 
      let [err, files, [entry]] = res as [any, string[], [FolderEntry, number, any]]; 
      if (err) { 
       entry.type = "error"; 
      } else if (files.indexOf('tiddlywiki.json') > -1) 
       entry.type = 'datafolder'; 
      return ([true, entry]); 
     }).reduce((n, [dud, entry]) => { 
      n.push(entry); 
      return n; 
     }, []).map(entries => { 
      return { entries, folder, tag }; 
     }) as Observable<{ entries: any, folder: any, tag: any }>; 
    }).subscribe(subscriber); 
} 

オリジナル:これは...書くために数時間を要し、それが動作します...しかし...それはconcatMapを使用していますので、それは一度に一つのリクエストを取ることができます。その目的のために書いたカスタム演算子を使用します。

export function statFileBatch(subscriber, input: Observable<any>) { 
    const signal = new Subject<number>(); 
    var count = 0; 
    //use set timeout to fire after the buffer recieves this item 
    const sendSignal = (item) => setTimeout(() => { count = 0; signal.next(item); }); 
    return input.concatMap(([folder, tag]) => { 
     return obs_readdir({ folder, tag })(folder); 
    }).lift({ 
     call: (subs: Subscriber<any>, source: Observable<any>) => { 
      const signalFunction = (count) => signal.mapTo(1), forwardWhenEmpty = true; 

      const waiting = []; 
      const _output = new Subject(); 

      var _count = new Subject<number>() 
      const countFactory = Observable.defer(() => { 
       return Observable.create(subscriber => { 
        _count.subscribe(subscriber); 
       }) 
      }); 

      var isEmpty = true; 
      const sourceSubs = source.subscribe(item => { 
       if (isEmpty && forwardWhenEmpty) { 
        _output.next(item); 
       } else { 
        waiting.push(item) 
       } 
       isEmpty = false; 
      }) 

      const pulse = new Subject<any>(); 
      const signalSubs = pulse.switchMap(() => { 
       return signalFunction(countFactory) 
      }).subscribe(count => { 
       //act on the closing observable value 
       var i = 0; 
       while (waiting.length > 0 && i++ < count) 
        _output.next(waiting.shift()); 
       //if nothing was output, then we are empty 
       //if something was output then we are not 
       //this is meant to be used with bufferWhen 
       if (i === 0) isEmpty = true; 

       _count.next(i); 
       _count.complete(); 
       _count = new Subject<number>(); 

       pulse.next(); 
      }) 
      pulse.next(); //prime the pump 

      const outputSubs = Observable.create((subscriber) => { 
       return _output.subscribe(subscriber); 
      }).subscribe(subs) as Subscription; 

      return function() { 
       outputSubs.unsubscribe(); 
       signalSubs.unsubscribe(); 
       sourceSubs.unsubscribe(); 
      } 
     } 
    }).mergeMap(([err, files, { folder, tag }]) => { 
     if (err) { sendSignal(err); return Observable.empty(); } 
     return Observable.from(files.map(a => [a, folder, files.length, tag])) as any; 
    }).mergeMap((res: any) => { 
     let [file, folder, fileCount, tag] = res as [string, string, number, any]; 
     return obs_stat([file, folder, fileCount, tag])(path.join(folder, file)) 
    }, 20).map(statFolderEntryCB).mergeMap<any, any>((res) => { 
     let [entry, [name, folder, fileCount, tag]] = res as [any, [string, string, number, any]]; 
     if (entry.type === 'folder') 
      return obs_readdir([entry, fileCount, tag])(path.join(entry.folder, entry.name)); 
     else return Observable.of([true, entry, fileCount, tag]); 
    }, 20).map((res) => { 
     //if (res === false) return (false); 
     if (res[0] === true) return (res); 
     let [err, files, [entry, fileCount, tag]] = res as [any, string[], [FolderEntry, number, any]]; 
     if (err) { 
      entry.type = "error"; 
     } else if (files.indexOf('tiddlywiki.json') > -1) 
      entry.type = 'datafolder'; 
     return ([true, entry, fileCount, tag]); 
    }).map(([dud, entry, fileCount, tag]) => { 
     count++; 
     if (count === fileCount) { 
      sendSignal([count, tag]); 
     } 
     return entry; 
    }).bufferWhen(() => signal).withLatestFrom(signal).map(([files, [sigResult, tag]]: any) => { 
     return [ 
      typeof sigResult !== 'number' ? sigResult : null, //error object 
      files,           //file list 
      typeof sigResult === 'number' ? sigResult : null, //file count 
      tag            //tag 
     ]; 
    }).subscribe(subscriber); 
} 
関連する問題