14
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【JavaScript】FileReaderをasync/awaitでエレガントに使いたい

Posted at

こんにちは。

皆さんもFileReaderを使う機会は多いと思います。
FileReaderは非同期なので、コールバック地獄に陥りがちです。

しかし最近のJavaScriptには、非同期なコードを同期的に扱えるasync/awaitという素晴らしい機能が存在します。

FileReaderもasync/awaitの恩恵を受けたい!!

解決策

class FileReaderEx extends FileReader{
    constructor(){
        super();
    }

    #readAs(blob, ctx){
        return new Promise((res, rej)=>{
            super.addEventListener("load", ({target}) => res(target.result));
            super.addEventListener("error", ({target}) => rej(target.error));
            super[ctx](blob);
        });
    }

    readAsArrayBuffer(blob){
        return this.#readAs(blob, "readAsArrayBuffer");
    }

    readAsDataURL(blob){
        return this.#readAs(blob, "readAsDataURL");
    }

    readAsText(blob){
        return this.#readAs(blob, "readAsText");
    }
}

元のFileReaderクラスをPromiseでラップした拡張クラスを作成して万事解決。
#readAs()は外部から見られたくないのでプライベートメソッドにしてあります。

ビフォーアフター

今までコールバックにまみれていたコードも...

Before
const reader1 = new FileReader();
reader1.addEventListener("load", ()=>{
    const buffer1 = reader1.result;

    const reader2 = new FileReader();
    reader2.addEventListener("load", ()=>{
        const buffer2 = reader2.result;

        const reader3 = new FileReader();
        reader3.addEventListener("load", ()=>{
            const buffer3 = reader3.result;
        });

        reader3.addEventListener("error", ()=>{
            alert(reader3.error.message);
        });

        reader3.readAsArrayBuffer(blob3);
    });

    reader2.addEventListener("error", ()=>{
        alert(reader2.error.message);
    });

    reader2.readAsArrayBuffer(blob2);
});

reader1.addEventListener("error", ()=>{
    alert(reader1.error.message);
});

reader1.readAsArrayBuffer(blob1);

async/awaitの手に掛かればこの通り!!

After
(async()=>{
    const buffer1 = await new FileReaderEx().readAsArrayBuffer(blob1);
    const buffer2 = await new FileReaderEx().readAsArrayBuffer(blob2);
    const buffer3 = await new FileReaderEx().readAsArrayBuffer(blob3);
})();

一目瞭然で見やすくなっています。

FileReader以外にも応用が利く、かなりオススメな手法です。

14
14
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
14
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?