1、回调地狱
多层回调函数相互嵌套就形成了回调地狱。
缺点:
- 代码耦合性太强,牵一发而动全身,难以维护
- 大量冗余的代码相互嵌套,代码的可读性变差
1.1、如何解决回调地狱的问题
为了解决回调地狱的问题,ES6(ECMAScript 2015)中新增了 Promise 的概念
1.2、promise的基本概念
1、promise是一个构造函数
- 可创建promise的实例 const p = new Promise
- new出来的promise实例对象代表一个异步操作
2、 promise.prototype上包含一个.then()方法
- 每一次new promise()构造函数得到的实例对象都可以通过原型链的方式访问到.then()方法
3、.then()方法用来预先指定成功和失败的回调函数
- p.then(成功的回调函数,失败的回调函数)
- p.then(result => {} ,error => {})
- 调用.then()方法时,成功的回调函数是必选的,失败的回调函数是可选的
2、基于 then-fs 读取文件内容
由于 node.js 官方提供的 fs 模块仅支持以回调函数的方式读取文件,不支持 Promise 的调用方式。因此,需要先运行 npm i then-fs 命令,安装 then-fs 这个第三方包,从而支持我们基于 Promise 的方式读取文件的内容
2.1、.then() 方法的特性
如果上一个 .then() 方法中返回了一个新的 Promise 实例对象,则可以通过下一个 .then() 继续进行处理。通过 .then() 方法的链式调用,就解决了回调地狱的问题。
2.2、基于 Promise 按顺序读取文件的内容
Promise 支持链式调用,从而来解决回调地狱的问题
fn(path.join('/files/1.txt','utf8'))
.then((res) => {
console.log(res);
return fn(path.join('/files/2.txt','utf8'))
}).then((res) => {
console.log(res);
return fn(path.join('/files/3.txt','utf8'))
}).then((res) => console.log(res))
2.3、通过 .catch 捕获错误
在 Promise 的链式操作中如果发生了错误,可以使用
Promise.prototype.catch
方法进行捕获和处理
如果不希望前面的错误导致后续的 .then 无法正常执行,则
可以将 .catch 的调用提前
fn(path.join('/files/1.txt','utf8'))
.catch(err=>{
console.log(err.message);
})
.then((res) => {
console.log(res);
return fn(path.join('/files/2.txt','utf8'))
}).then((res) => {
console.log(res);
return fn(path.join('/files/3.txt','utf8'))
}).then((res) => console.log(res))
2.4
Promise.all() 方
法
promise.all()方法会发起并行的Promise异步操作,等所有的异步操作结束之后才会执行下一步的.then操作(等待机制)。
import thenFs from 'then-fs'
const promiseArr = [
thenFs.readFile('./files/1.txt', 'utf8'),
thenFs.readFile('./files/2.txt', 'utf8'),
thenFs.readFile('./files/3.txt', 'utf8')
]
Promise.all(promiseArr).then(([r1, r2, r3]) => {
console.log(r1, r2, r3)
})
2.5 Promise.race() 方法
promise.race会发起并行的promise异步操作,只要任何一个异步操作完成,就会立即执行下一步的.then操作(赛跑机制)。
3、封装一个自己的promise函数
import fs from 'fs'
function getFile(fpath) {
return new Promise(function (resolve,reject) {
fs.readFile(fpath, 'utf8', (err, data) => {
if (err) return reject(err)
resolve(data)
})
})
}
getFile('./files/1.txt').then((r1)=>{console.log(r1)},(err)=>{console.log(err.message)})