今更ながら非同期でハマったのでメモ。
非同期処理を同期的に書くなら、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/await
とPromise
を上手く組み合わせると良いです。
それぞれ単体で使うことは知ってても、組み合わせはハマって初めて知る気がします・・・。
追記
↑のコードだと、ディレクトリ下に100件以上あると全て取得できない。
ドキュメントにも書いてあった。
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()
するなりして、配列に落としておいた方が無難かも。