Javascript和Typescript下如何通过 async/await 优雅地使用 FileReader

Javascript和Typescript下如何通过 async/await 优雅地使用 FileReader

FileReader的使用机会很多,但是它是异步的,因此很容易出现回调地狱。

我们可以使用async/await特性,它允许我们以同步的方式调用异步代码。

封装成方法

javascript 复制代码
export async function readTextFile(file: File) {
    const reader = new FileReader();
    reader.readAsText(file);
    return new Promise((resolve, reject) => {
        reader.onload = () => resolve(reader.result);
        reader.onerror = () => reject(reader.error);
    });
}

export async function readBinaryFile(file: File) {
    const reader = new FileReader();
    reader.readAsArrayBuffer(file);
    return new Promise((resolve, reject) => {
        reader.onload = () => resolve(reader.result);
        reader.onerror = () => reject(reader.error);
    });
}

export async function readAsText(file: File) {
    const reader = new FileReader();
    reader.readAsText(file);
    return new Promise((resolve, reject) => {
        reader.onload = () => resolve(reader.result);
        reader.onerror = () => reject(reader.error);
    });
}

使用方法:

typescript 复制代码
(async()=> {
    const buffer1 = await readTextFile(file);
    const buffer2 = await readBinaryFile(file);
    const buffer3 = await readAsText(file);
})();

Javascript封装成一个class

javascript 复制代码
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");
    }
}

使用方法:

javascript 复制代码
(async()=>{
    const buffer1 = await new FileReaderEx().readAsArrayBuffer(blob1);
    const buffer2 = await new FileReaderEx().readAsDataURL(blob2);
    const buffer3 = await new FileReaderEx().readAsText(blob3);
})();

TypeScript封装成一个class

typescript 复制代码
export class FileReaderEx extends FileReader {
    constructor() {
        super();
    }

    private readAs(blob: Blob, ctx: 'readAsArrayBuffer' | 'readAsDataURL' | 'readAsText') {
        return new Promise((res, rej) => {
            super.addEventListener("load", ({target}) => res(target?.result));
            super.addEventListener("error", ({target}) => rej(target?.error));

            super[ctx](blob);
        });
    }

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

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

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

使用方法:

javascript 复制代码
(async()=>{
    const buffer1 = await new FileReaderEx().readAsArrayBuffer(blob1);
    const buffer2 = await new FileReaderEx().readAsDataURL(blob2);
    const buffer3 = await new FileReaderEx().readAsText(blob3);
})();

TypeScript基于泛型

typescript 复制代码
/**
 * @description 同步调用包装
 * @param promise 需要被调用的异步方法
 */
async function asyncWrap<T = any>(promise: Promise<T>): Promise<T | null> {
    try {
        return await promise;
    } catch (err) {
        return null;
    }
}

export async function fileReaderWrap<T = any>(blob: Blob, ctx: 'readAsArrayBuffer' | 'readAsDataURL' | 'readAsText'): Promise<any> {
    const reader = new FileReader();
    reader[ctx](blob);
    return new Promise((resolve, reject) => {
        reader.onload = () => resolve(reader.result);
        reader.onerror = () => reject(reader.error);
    });
}

使用方法:

typescript 复制代码
(async()=>{
    const buffer1 = await asyncWrap<ArrayBuffer>(fileReaderWrap<ArrayBuffer>(file, 'readAsArrayBuffer'));
    const buffer2 = await asyncWrap<ArrayBuffer>(fileReaderWrap<ArrayBuffer>(file, 'readAsDataURL'));
    const buffer3 = await asyncWrap<ArrayBuffer>(fileReaderWrap<ArrayBuffer>(file, 'readAsText'));
})();

参考资料

相关推荐
kyriewen14 分钟前
WebAssembly:前端界的“外挂”,让C++代码在浏览器里跑起来
前端·c++·webassembly
悟空和大王16 分钟前
核心 SDK 详细设计文档 (Visual-Render-SDK)
前端
空中海19 分钟前
02 状态、Hooks、副作用与数据流
开发语言·javascript·ecmascript
空中海40 分钟前
04 React Native工程化、质量、发布与生态选型
javascript·react native·react.js
AI砖家1 小时前
Claude Code Superpowers 安装使用指南:让 AI 编程从“业余”走向“工程化”
前端·人工智能·python·ai编程·代码规范
李白的天不白1 小时前
webpack 与axios 版本冲突问题
前端·webpack·node.js
杨超凡1 小时前
豆包收费了?我特么自己用“意念”搓了一个!
javascript
Java后端的Ai之路1 小时前
模型调好了怎么给老板看?用这玩意儿5分钟出Demo,连前端都不用学:Gradio 6全栈实战指南
前端·机器学习·gradio
木斯佳1 小时前
前端八股文面经大全:中科星图前端日常实习(2026-04-29)·面经深度解析
前端