LoginSignup
7
7

More than 1 year has passed since last update.

FileReader APIをPromise化する方法

Last updated at Posted at 2022-04-07

変更歴

2022/09/21

  • `reader.onload`のところを、`reader.addEventListener("load", () => ...)`というように変更しました。
    通常、JavaScriptではel.onclick = () => {}というように、.onを使ってEventListenerを追加するやり方は推奨されていないのです。
  • Promiseの型にstringの型を追加しました。
    TypeScriptインタプリタはエラーを吐くので、resolveする前に型チェックを入れる必要があります。

概要

フロントエンドのWebアプリでユーザーが指定したファイルをアップロードする前に、Base64に変換することが常套手段です。
その理由は、Base64はファイルサイズが多少大きくなるが、データ破壊を防げるからです。

2進コードファイルをブラウザでBase64に変換するには、FileReader APIを使います。

ただ、このFileReader APIはかなり古いようで、なんと、Promiseに対応していないのです!

そこで、そのFileReader APIをPromiseに包む、Promise化の方法をここでご紹介します。

コード

ブラウザのHTMLInputElementから取ったFileListを引数としてもらいます。

ファイル一つのみの場合は以下のように使います。

const convertToB64 = (filesList: FileList) =>
  new Promise<string>((resolve, reject) => {
    const file = filesList[0];
    const reader = new FileReader();

    reader.addEventListener("load", () => {
      const { result } = reader;
      if (typeof result !== "string") throw TypeError("Reader did not return string.");
      resolve(result);
    });

    reader.addEventListener("error", () => {
      reject(reader.error);
    });

    reader.readAsDataURL(file);
  });

複数の場合はPromise.allを使います。

const convertAllToB64 = (filesList: FileList) =>
  Promise.all(
    Array.from(filesList).map(
      (file) =>
        new Promise<string>((resolve, reject) => {
          const reader = new FileReader();

          reader.addEventListener("load", () => {
            const { result } = reader;
            if (typeof result !== "string") throw TypeError("Reader did not return string.");
            resolve(result);
          });

          reader.addEventListener("error", () => {
            reject(reader.error);
          });

          reader.readAsDataURL(file);
        })
    )
  );

これらのPromiseが解決されたら、Fetch APIなどでサバーに送るなりすればいいです。

注意点

FileReader APIのreadAsDataURLは、Data URI Schemeになっています。Base64の前に、data:image/png;base64,を追加しているのです。
これをsplit(",")[1]などでBase64だけを取ることができます。
このままBase64からHexなどに変換しようとすると、フォーマットが変になるのでご注意ください。

まとめ

以上、FileReader APIの簡単なPromise化方法をご紹介しました!FileReader APIには他のフォーマットに変換する機能があるので、必要に応じて変えればいいと思います。

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7