JavascriptのFileReaderは非同期的に実行され、onloadイベントの中で取得結果を処理するというのが一般的な使い方だと思います。
今回、このFileReaderの取得結果をonloadの中で処理するのではなく、グローバル変数に格納する方法について共有したいと思います。
目次
通常のFileReaderの使い方
おそらく通常のFileReaderは下記のように記述すると思います。
Blob(またはFile)をdata URLに変換するリクエストをして、onloadイベントの中で結果を取得して処理をしていくというものですね。
onloadの中でしか続きを書けないという制限があります。
let blob = new Blob(["hoge"], {type: 'image/png'})
let reader = new FileReader()
reader.readAsDataURL(blob)
reader.onload = function() {
dataUrl = reader.result
//取得したdata URLに対する処理
.
.
.
}
FileReaderの結果をグローバル変数に入れようとしてみる
FileReaderの結果をグローバル変数に入れようとしてみると、下記のようなコードを思いつきます。
しかしこれはうまく動きません。
dataUrl変数にはundefinedが入ってしまいます。
let blob = new Blob(["hoge"], {type: 'image/png'})
let dataUrl = ''
let reader = new FileReader()
reader.readAsDataURL(blob)
reader.onload = function() {
dataUrl = reader.result
}
console.log(dataUrl) //undefinedが入ってしまう
FileReaderの結果をグローバル変数に格納する正しいやり方
async/awaitとPromiseを使うとFileReaderの結果をグローバル変数に格納することができます。
6行目はFileReaderのonload⇒resolveメソッド⇒Promiseが完了 という流れになります。
awaitでPromiseの処理を待っているので、7行目で結果を変数に格納できるということになります。
;(async function() {
let blob = new Blob(["hoge"], {type: 'image/png'})
let reader = new FileReader()
reader.readAsDataURL(blob)
await new Promise(resolve => reader.onload = () => resolve());
dataUrl = reader.result
console.log(dataUrl) //data URLが入っている
})()
awaitはasync関数の中でしか使えません。上記では最終行に()を付けることでasync関数を即時関数として実行しています。なのでawaitを使う可能性がある時はすべてのコードをasync即時関数で囲ってしまってもいいのではないかなと思います。(下記のようなイメージ)
;(async function() {
//なにかしらの記述
//なにかしらの記述
//なにかしらの記述
//なにかしらの記述
let blob = new Blob(["hoge"], {type: 'image/png'})
let reader = new FileReader()
reader.readAsDataURL(blob)
await new Promise(resolve => reader.onload = () => resolve());
dataUrl = reader.result
//なにかしらの記述
//なにかしらの記述
//なにかしらの記述
//なにかしらの記述
})()
FileReaderの取得処理を関数としてまとめる
Promiseの記述が凡雑になるので、関数としてまとめてしまうと使いやすいです。
async function convert2DataUrl(blobOrFile) {
let reader = new FileReader()
reader.readAsDataURL(blobOrFile)
await new Promise(resolve => reader.onload = () => resolve())
return reader.result
}
下記のように使います。手続きのコードがとてもすっきりしました。
;(async function() {
//なにかしらの記述
//なにかしらの記述
//なにかしらの記述
//なにかしらの記述
let blob = new Blob(["hoge"], {type: 'image/png'})
let dataURL = await convert2DataUrl(blob)
//なにかしらの記述
//なにかしらの記述
//なにかしらの記述
//なにかしらの記述
})()
async function convert2DataUrl(blobOrFile) {
let reader = new FileReader()
reader.readAsDataURL(blobOrFile)
await new Promise(resolve => reader.onload = () => resolve())
return reader.result
}
下記の記事を参考にさせていただきました。
実例で学ぶPromise (2)
以上、FileReaderの取得結果を変数に入れる方法でした!