JavaScript 中使用 Promise 封装 FileReader 实现异步文件读取

作者:小括号

时间:2026-10-29

浏览:380

本文介绍如何利用 ES6 Promise 封装浏览器原生 FileReader API,将基于回调的事件驱动模型转换为链式调用的异步流程。通过示例展示如何封装文件读取逻辑,处理成功与失败状态,并实现链式操作以简化代码结构。

文章目录

Promise 异步处理概述

在处理异步任务时,Promise 是极佳的选择,它能有效减少代码嵌套层级,提升可读性并使逻辑更加清晰。ES6 已将 Promise 纳入标准规范,jQuery 3.0 也通过修改实现以贴近该规范(参见 3.0 发布公告)。虽然部分新增 API 如 .fetch() 原生支持 “thenable”,但大多数传统 API 仍依赖回调函数。通过重新封装这些 API,我们可以避免嵌套陷阱,享受 Promise 带来的便利。

Promise 基本用法

Promise 的一般用法 首先了解 Promise 的基本使用方式。


// 声明 Promise 对象
var p = new Promise(function (resolve, reject) {
 // 不管啥时候,该执行then了,就调用 resolve
 setTimeout(function () { 
  resolve(1);
 }, 5000);

 // 或者不管啥问题,就调用 reject
 if (somethingWrong) {
  reject('2');
 }   
});
  
// 使用 Promise 对象
p.then(function (num) {
 // 对应上面的 resolve
 console.log(num); // 1
}, function (num) {
 // 对应上面的 reject
 console.log(num); // 2
});

Promise 的驱动模型相对简单:任何操作均可假定为两种结果,成功或失败。只需在适当时机调用相应的程序,进入后续步骤即可。.then() 方法顾名思义表示“下一步”,当先前的 Promise 产生结果——即调用 resolve 或 reject——后,便会启动对应的处理函数。

Promise 实例一旦创建便会立即执行,判定结果需由开发者自行决定,例如加载成功或满足特定条件等。通过串联 .then() 可以执行一系列操作。每次调用 .then() 都会生成一个新的 Promise 实例,该实例会等待前一个实例状态改变后再开始执行。

封装 FileReader 实现

封装 FileReader 接下来进行封装。思路十分简单:FileReader 除了提供多种 read 方法外,还包含几个事件钩子,其中 onerror 和 onload 显然可作为判断任务是否完成的依据。若加载成功,则需要获取文件内容,因此将文件或文件内容传递至下一步也是必要的。

最终完成的代码如下:


function reader (file, options) {
 options = options || {};
 return new Promise(function (resolve, reject) {
  let reader = new FileReader();

  reader.onload = function () {
   resolve(reader);
  };
  reader.onerror = reject;

  if (options.accept && !new RegExp(options.accept).test(file.type)) {
   reject({
    code: 1,
    msg: 'wrong file type'
   });
  }

  if (!file.type || /^text\//i.test(file.type)) {
   reader.readAsText(file);
  } else {
   reader.readAsDataURL(file);
  }
 });
}

为了使其真正具备实用价值,代码中还包含了一些验证文件类型的操作,但这与本文主旨无关,此处略过。这段代码的核心在于创建一个 Promise 对象,等待 FileReader 读取完成后调用 resolve 方法,或在出现问题时调用 reject 方法。

封装函数的使用与链式调用

使用刚才封装好的函数 接下来便可在项目中直接使用了:


reader(file)
 .then(function (reader) {
  console.log(reader.result);
 })
 .catch(function (error) {
  console.log(error);
 });

.then() 支持两个参数,第一个参数在 Promise 成功时启动,第二个参数则在失败时启动。使用 .catch() 也能实现相同的效果。Promise 的优势除了提升代码可读性外,返回的 Promise 对象还可以任意传递,继续进行链式调用,具有极大的扩展空间。

继续 .then() 因此,我们可以串联更多操作(原本计划编写断点续传功能,后续再讨论):

全选复制放进笔记reader(file)


 .then(function (reader) {
  return new Promise(function (resolve, reject) {
   // 就随便暂停个5秒吧……
   setTimeout(function () {
    resolve(reader.result); 
   }, 5000);
  });
 })
 .then(function (content) {
  console.log(content);
 });

以上就是本文的全部内容,希望对大家的学习有所帮助。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章