目录
Promise
1. 回调地狱
1.1 如何解决回调地狱的问题
1.2 Promise 的基本概念
2. 基于回调函数按顺序读取文件内容
3. 基于 then-fs 读取文件内容
3.1 then-fs 的基本使用
3.2 .then() 方法的特性
3.3 基于 Promise 按顺序读取文件的内容
3.4 通过 .catch 捕获错误
3.5 Promise.all() 方法
3.6 Promise.race() 方法
4. 基于 Promise 封装读文件的方法
4.1 getFile 方法的基本定义
4.2 创建具体的异步操作
4.3 获取 .then 的两个实参
4.4 调用 resolve 和 reject 回调函数
最后
Promise
1. 回调地狱
多层回调函数的相互嵌套,就形成了回调地狱。示例如下:
回调地狱的缺点:
-
代码耦合性太强,牵一发而动全身,难以维护
-
大量冗余的代码相互嵌套,代码的可读性变差
1.1 如何解决回调地狱的问题
为了解决回调地狱的问题,ES6(ECMAScript 2015)中新增了 Promise 的概念。
1.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 的方式读取文件的内容:
npm install then-fs
3.1 then-fs 的基本使用
调用 then-fs 提供的 readFile() 方法,可以异步地读取文件的内容,它的返回值是 Promise 的实例对象。因
此可以调用 .then() 方法为每个 Promise 异步操作指定成功和失败之后的回调函数。示例代码如下:
import thenFs from 'then-fs'
thenFs.readFile('./files/1.txt', 'utf8').then((r1) => {console.log(r1)})
thenFs.readFile('./files/2.txt', 'utf8').then((r2) => {console.log(r2)})
thenFs.readFile('./files/3.txt', 'utf8').then((r3) => {console.log(r3)})
注意:上述的代码无法保证文件的读取顺序,需要做进一步的改进!
3.2 .then() 方法的特性
如果上一个 .then() 方法中返回了一个新的 Promise 实例对象,则可以通过下一个 .then() 继续进行处理。通
过 .then() 方法的链式调用,就解决了回调地狱的问题。
3.3 基于 Promise 按顺序读取文件的内容
Promise 支持链式调用,从而来解决回调地狱的问题。示例代码如下:
import thenFs from 'then-fs'
thenFs
.readFile('./files/11.txt', 'utf8') //返回值是 Promise 的实例对象
.catch((err) => {
console.log(err.message)
})
.then((r1) => {
console.log(r1)
return thenFs.readFile('./files/2.txt', 'utf8')
})
.then((r2) => {
console.log(r2)
return thenFs.readFile('./files/3.txt', 'utf8')
})
.then((r3) => {
console.log(r3)
})
3.4 通过 .catch 捕获错误
在 Promise 的链式操作中如果发生了错误,可以使用 Promise.prototype.catch 方法进行捕获和处理:
import thenFs from 'then-fs'
thenFs.readFile('./files/1.txt','utf8').then((r1)=>{
console.log(r1)
return thenFs.readFile('./files/22.txt','utf8')
.catch( err =>{ //通过 catch 捕获错误。但是从这里往后就不会捕获了。
console.log(err)
})
}).then((r2)=>{
console.log(r2)
return thenFs.readFile('./files/3.txt','utf8')
}).then((r3)=>{
console.log(r3)
})
//运行结果是 读取出 r1 r2打印undefined r3
//如果把 catch 放到最后,则遇到错误以后爆错误,错误后面就不会再执行了
//在这里把 catch 放到最后,就能读取出 r1 ,然后就爆err了,r2 ,r3 都不会读取出来
如果不希望前面的错误导致后续的 .then 无法正常执行,则可以将 .catch 的调用提前
3.5 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)
})
.catch(err=>{
console.log(err)
})
注意:数组中 Promise 实例的顺序,就是最终结果的顺序!
3.6 Promise.race() 方法
Promise.race() 方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就立即执行下一步的
.then 操作(赛跑机制)。
示例代码如下:
import thenFs from 'then-fs'
const promiseArr = [
thenFs.readFile('./files/3.txt', 'utf8'),
thenFs.readFile('./files/2.txt', 'utf8'),
thenFs.readFile('./files/1.txt', 'utf8'),
]
Promise.race(promiseArr).then(result => {
console.log(result)
})
//最后就打印出一个,哪个读取快就打印哪个,读取出一个就立马停止后面的读取。
//有可能出r1 ,有可能出r3,不固定,谁快读取谁!
4. 基于 Promise 封装读文件的方法
方法的封装要求:
① 方法的名称要定义为 getFile
② 方法接收一个形参 fpath,表示要读取的文件的路径
③ 方法的返回值为 Promise 实例对象
4.1 getFile 方法的基本定义
// 1.方法的名称为 getFile
// 2.方法接收一个形参 fpath, 表示要读取的文件的路径
function getFile(fpath) {
//3.方法的返回值为 Promise 的实例对象
return new Promise()
}
注意:第 5 行代码中的 new Promise() 只是创建了一个形式上的异步操作。
4.2 创建具体的异步操作
如果想要创建具体的异步操作,则需要在 new Promise() 构造函数期间,传递一个 function 函数,将具体的
异步操作定义到 function 函数内部。
4.3 获取 .then 的两个实参
通过 .then() 指定的成功和失败的回调函数,可以在 function 的形参中进行接收。
4.4 调用 resolve 和 reject 回调函数
Promise 异步操作的结果,可以调用 resolve 或 reject 回调函数进行处理。
示例代码如下:
import fs from 'fs'
function getFile(fpath) {
return new Promise(function (resolve, reject) {
fs.readFile(fpath, 'utf8', (err, dataStr) => {
if (err) return reject(err)
resolve(dataStr)
})
})
}
getFile('./files/11.txt')
.then((r1) => {
console.log(r1)
})
.catch((err) => console.log(err.message))
最后
星月前端博客https://xingyue.vercel.app/
个人博客,记录前端学习笔记,欢迎收藏或者提意见。