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'));
})();

参考资料

相关推荐
山有木兮木有枝_15 分钟前
JavaScript 设计模式--单例模式
前端·javascript·代码规范
张志鹏PHP全栈16 分钟前
TypeScript 第二天,TypeScript中的类型(一)
typescript
一大树29 分钟前
Vue3 开发必备:20 个实用技巧
前端·vue.js
颜渊呐34 分钟前
uniapp中APPwebview与网页的双向通信
前端·uni-app
10年前端老司机1 小时前
React 受控组件和非受控组件区别和使用场景
前端·javascript·react.js
夏晚星1 小时前
vue实现微信聊天emoji表情
前端·javascript
停止重构1 小时前
【方案】前端UI布局的绝技,响应式布局,多端适配
前端·网页布局·响应式布局·grid布局·网页适配多端
極光未晚1 小时前
TypeScript在前端项目中的那些事儿:不止于类型的守护者
前端·javascript·typescript
ze_juejin1 小时前
Vue3 + Vite + Ant Design Vue + Axios + Pinia 脚手架搭建
前端·vue.js
Rrvive1 小时前
原型与原型链到底是什么?
javascript