typeof Diary

VimとかJSとか。やったことのメモ。自分のため。

非同期を同期的に

今更ながら非同期でハマったのでメモ。

非同期処理を同期的に書くなら、async/awaitで良いのですが、
これがディレクトリの中身を読むやつみたいな場合...

const entries = []
if (entry.isDirectory) {
  const reader = entry.createReader()
  reader.readEntries(entry => {
    entries.push(entry)
  })
}

// entriesを使った処理

このままだと、readEntriesが非同期なので、後半の処理は思い通りにはいきません。

const _entries = new Promise(resolve => reader.readEntries(entry => resolve(entry)))
entries.push(..._entries)

async/awaitPromiseを上手く組み合わせると良いです。 それぞれ単体で使うことは知ってても、組み合わせはハマって初めて知る気がします・・・。

追記

↑のコードだと、ディレクトリ下に100件以上あると全て取得できない。

developer.mozilla.org

ドキュメントにも書いてあった。

Note that to read all files in a directory, readEntries needs to be called repeatedly until it returns an empty array. In Chromium-based browsers, the following example will only return a max of 100 entries.

if (entry.isDirectory) {
  const reader = entry.createReader()
  const readDir = async _entries => {
    await new Promise(resolve => {
      reader.readEntries(async entry => {
        if (entry.length !== 0) {
          _entries.push(...entry)
          await readDir(_entries)
        }
        return resolve(_entries)
      })
    })
    return Promise.resolve(_entries)
  }
  entries.push(...(await readDir([])))
} else {
  entries.push(entry)
}

こんな感じでどうですかね。。。
もっとスマートなやり方ありますか・・・。

さらに加えると、これ、いきなりfor (let item of e.dataTransfer.items)すると、
複数ドラッグしてるとき、最初以外が消えます。
なので、最初にitem.webkitGetAsEntry()するなりして、配列に落としておいた方が無難かも。