😼

画像の読み込みをPromiseで制御する

2021/09/01に公開

画像を読み込んだタイミングで次の挙動に移って欲しい時があると思います。
そういった時にPromiseを使う事でJavaScript内で画像のロードタイミングに合わせて、Promiseを解消できる形にしました。

Promiseやasync/awaitに関しては、以下の記事にも書いているので、興味があれば合わせて読んでください。
https://zenn.dev/nana/articles/ff65486fcd0e34

読み込みを制御するとはどういうことか

例えば、プロフィール画像などを設定する時に、プレビュー画像というのが出ると思います。
そのプレビュー画像のところに表示させているのは、画像をbase64形式にしたもので、画像を文字として扱うためのものです。

そのプレビューを表示させるために、画像を設定し、読み込んだ(画像を認識した)後に、該当箇所にその画像のbase64の文字列を当てはめることでプレビューとして表示します。

この読み込むタイミングの後に何か処理を挟みたい、もしくは読み込んでbase64を当てはめた後に実行したい処理をする場合、base64を当てはめるまで待たせる必要があります。
この時にPromiseを使って、解決させるタイミングで次の処理にいけるようにしました。

読み込むタイミングはonloadで

imageが読み込まれる時にPromiseを解決します。
imageが読み込まれる時というのは、imgタグのsrcにbase64画像がセットされる時です。
つまり

js
$image.src = base64:XXXXXXXX

このようにして読み込んだ時ということですね。
この時の$imageは、実際のDOMでも、JavaScriptで作り出したImageでも同じです。

JavaScriptでImageを作る
const image = new Image()

このimageへのsrc属性に対してロードが完了した時点でPromiseを解消します。

Promiseの解消
const imgLoad = () => {
    const image = new Image()
    image.crossOrigin = 'anonymous'
    image.width = 500
    image.height = 300
    
    return new Promise(resolve => {
      image.onload = () => {
        resolve(image)
      }
      image.src = 'base64:XXXXXXXX'
    })
}

onloadに画像のsrcが読み込まれたタイミングで実行する事を前もって、imageに仕込んでおいて
読み込みが完了するとonloadの処理が走るという流れになります。

この時、TypeScriptを使っていた場合、Promiseのジェネリクスはresolveで解消する時に渡されるデータ型になります。
文字列の場合

ts例
return Promise<string>(resolve => {
  resolve('string')
})

エラーも制御できる

先ほどのonloadをerror発生イベントに変えるだけです。

Error時
const imgLoad = () => {
    const image = new Image()
    image.crossOrigin = 'anonymous'
    image.width = 500
    image.height = 300
    
    return new Promise((resolve, reject) => {
      image.onload = () => {
        resolve(image)
      }
      image.onerror = (error) => {
        reject(error)
      }
      image.src = 'base64:XXXXXXXX'
    })
}

このロードを待つ事によって、画像に対してロードのタイミングで処理を挟む事もできますし
後続の処理を待たせる事もできます。

参考

https://qiita.com/PlanetMeron/items/2905e2d0aa7fe46a36d4

https://qiita.com/narupo/items/79660842609b87cf402e

https://qiita.com/sin_tanaka/items/b17a099d2a6a5e9a94b7

https://observablehq.com/@severo/async-image-loading-and-cors

Discussion