フロントエンド開発Blog

オレには鈍器がある

FIleAPI , JavaScript

フォルダをドラッグアンドドロップするとファイル一覧を出力するだけのWEBアプリです。
ロジック的には単純で、

  1. dataTransfer.itemsから最初のFileをエントリーポイントと定義
  2. エントリーポイントの該当階層を探査し、ファイルならパスを取得、ディレクトリなら更にエントリーポイントとして再帰処理
  3. ディレクトリが見つからなくなるまで処理を続け、最後に出力

という感じです。

ただ、全ファイルの探査が完了したか否かのロジックのためにPromiseを入れ子にしている点がちょっと変わっているなーと自分事ながら思います。母数が不明な非同期処理における終端を判定するひとつの解としてみていただければと。。

readEntriesはAsyncなためPromiseを使いました。
全てのディレクトリの探査が終わるタイミングを関数的にさっと取得できそうになかったため、Promiseを入れ子にしてあります。

ディレクトリが見つかった時点ですぐさま(同期処理)numDir++し、「ディレクトリ処理中」フラグを追加します。
中のほうのPromiseは純粋にreadEntriesの終了タイミングでディレクトリ内のentryに対して再帰処理を実行しつつ「該当ディレクトリの処理は完了したよ」とフラグを折ります(numDir--)numDirが0になったら外側のPromiseに対してresolveを通知します。

numDirを足すときは同期処理で、折るときは非同期処理のため、理論上は「中途半端なところでnumDirが0になってしまう」ことはないはずです。

ディレクトリ構造とかヒープ構造などで、1つの頂点から末端へ向かう場合は、今回のように「ここは末端か否か」という判定に苦心します。ヒープツリー構造などで、最初の時点で母数が分かれば比較的簡単に終端が分かります(外部記憶としてint型のcount変数を用意し、処理時にcount++し、母数==countなら終端と判定する)

Promiseに限って言えば、allやwhenのように「全部終わったらthenに向かう」という方法もあります。ですがこれも最初の時点で母数が分かっていないと難しい。再帰処理の中でPromiseで処理したい非同期処理(ここではreadEntries)が増えていくケースでは利用できません。

結局、処理開始時にインクリメントし、処理後にデクリメントするというカウンター方式が最もシンプルですね。

:閑話休題:
経理関係の話で「お金の入りは早く、出は遅く」という言葉を聴いたことがあります。
あれは同期で足して非同期で減らしていたのかな、とか思ったりした初夏の夜。

ページトップへ

関連ページ

ページトップへ