1. 回调地狱
多层回调函数的相互嵌套,就形成了回调地狱。示例代码如下:
回调地狱的缺点:
代码耦合性太强,牵 一 发而 动 全 身 , 难 以维护
大量冗余的代码相互 嵌 套, 代 码 的 可读 性 变差
1.1 如何解决回调地狱的问题
为了解决回调地狱的问题,ES6(ECMAScript 2015)中新增了 Promise 的概念。
2.Promise 的基本概念
① Promise 是一个构造函数
我们可以创建 Promise 的实 例 const p = new Promise()
new 出来的 Promise 实例对象, 代表一个 异 步操作
② Promise.prototype 上包含一个.then() 方法
每一 次 new Promise() 构造函数得到的实例 对 象,
都可 以 通过原型链的 方 式 访 问 到 .then() 方法,例 如 p.then()
③ .then() 方法用来预先指定成功和失败的回调函数
p.then( 成功的回调 函 数 , 失 败 的 回 调 函 数 )
p.then( result => { }, error => { })
调 用 .then() 方法时,成功的回调 函 数是 必 选 的 、失 败 的回 调 函 数 是可 选 的
2.1 基于回调函数按顺序读取文件内容
3. 基于 then-fs 读取文件内容
由于node.js 官方提供的fs 模块仅支持以回调函数的方式读取文件,不支持 Promise 的调用方式。因此,需 要先运行如下的命令,安装then-fs 这个第三方包,从而支持我们基于 Promise 的方式读取文件的内容:
3.1 then-fs 的基本使用
调用then-fs 提供的readFile() 方法,可以异步地读取文件的内容,它的返回值是 Promise 的实例对象。因 此可以调用.then() 方法为每个 Promise 异步操作指定成功和失败之后的回调函数。示例代码如下:
注意:上述的代码无法保证文件的读取顺序,需要做进一步的改进!
3.2 .then() 方法的特性
如果上一个 .then() 方法中返回了一个新的 Promise 实例对象,则可以通过下一个 .then() 继续进行处理。通
过 .then() 方法的链式调用,就解决了回调地狱的问题。
3.3 基于 Promise 按顺序读取文件的内容
Promise 支持链式调用,从而来解决回调地狱的问题。示例代码如下:
3.4 通过 .catch 捕获错误
在 Promise 的链式操作中如果发生了错误,可以使用 Promise.prototype.catch 方法进行捕获和处理:
如果不希望前面的错误导致后续的 .then 无法正常执行,则可以将 .catch 的调用提前,示例代码如下:
3.5 Promise.all() 方法
Promise.all() 方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的 .then
操作(等待机制)。示例代码如下:
注意:数组中 Promise 实例的顺序, 就是最终结果的顺序!
3.6 Promise.race() 方法
Promise.race() 方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就立即执行下一步的.then 操作(赛跑机制)。示例代码如下:
4. 基于 Promise 封装读文件的方法
方法的封装要求:
① 方法的名称要定义为getFile
② 方法接收一个形参fpath,表示要读取的文件的路径
③ 方法的返回值为 Promise 实例对象
4.1 getFile 方法的基本定义
注意:第 5 行代码中的new Promise() 只是创建了一个形式上的异步操作。
4.2 创建具体的异步操作
如果想要创建具体的异步操作,则需要在new Promise() 构造函数期间,传递一个function 函数,将具体的 异步操作定义到function 函数内部。示例代码如下:
4.3 获取 .then 的两个实参
通过.then() 指定的成功和失败的回调函数,可以在function 的形参中进行接收,示例代码如下:
4.4 调用 resolve 和 reject 回调函数
Promise 异步操作的结果,可以调用resolve 或 reject 回调函数进行处理。示例代码如下:
5. async/await
5.1. 什么是 async/await
async/await 是 ES8(ECMAScript 2017)引入的新语法,用来简化 Promise 异步操作。在 async/await 出 现之前,开发者只能通过链式.then() 的方式处理 Promise 异步操作。示例代码如下:
.then 链式调用的优点: 解决了回调地狱的问题
.then 链式调用的缺点: 代码冗余、阅读性差、 不易理解
5.2. async/await 的基本使用
使用 async/await 简化 Promise 异步操作的示例代码如下:
5.3. async/await 的使用注意事项
① 如果在function 中使用了 await,则 function 必须被 async 修饰
② 在 async 方法中,第一个 await 之前的代码会同步执行,await 之后的代码会异步执行