Promise 异步用法
创始人
2024-05-29 23:01:31
0

一、回调地狱

多层回调函数的相互嵌套,就形成了回调地狱。示例代码如下:

回调地狱的缺点:

  • 代码耦合性太强,牵一发而动全身,难以维护
  • 大量冗余的代码相互嵌套,代码的可读性变差

如何解决回调地狱的问题?

为了解决回调地狱的问题,ES6(ECMAScript 2015)中新增了 Promise 的概念 

二、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 基于回调函数按顺序读取文件内容

import fs from 'fs'// 读取 1.txt文件
fs.readFile('./files/1.txt','utf8',(err1,r1)=>{if(err1) return console.log(err1.message) // 读取 文件1 失败console.log(r1)// 读取 文件1 成功// 读取 2.txt文件fs.readFile('./files/2.txt','utf8',(err2,r2)=>{if(err1) return console.log(err2.message) // 读取 文件2 失败console.log(r2)// 读取 文件1 成功// 读取 3.txt文件fs.readFile('./files/3.txt','utf8',(err3,r3)=>{if(err3) return console.log(err3.message) // 读取 文件3 失败console.log(r3) // 读取 文件1 成功})})
})// 结果:
// txt file 1
// txt file 2
// txt file 3

2.2 基于 then-fs 读取文件内容

由于 node.js 官方提供的 fs 模块仅支持以回调函数的方式读取文件,不支持 Promise 的调用方式。因此,需要先运行如下的命令,安装 then-fs 这个第三方包,从而支持我们基于 Promise 的方式读取文件的内容:

npm install then-fs

调用 then-fs 提供的 readFile() 方法,可以异步地读取文件的内容,它的返回值是 Promise 的实例对象。因此, 可以调用 .then() 方法为每个 Promise 异步操作指定成功和失败之后的回调函数。示例代码如下:

import thenFs from 'then-fs'
thenFs.readFile("./files/1.txt",'utf8').then(r1=>{console.log(r1)},err1=>{console.log(err1.message)})
thenFs.readFile("./files/2.txt",'utf8').then(r2=>{console.log(r2)},err2=>{console.log(err2.message)})
thenFs.readFile("./files/3.txt",'utf8').then(r3=>{console.log(r3)},err3=>{console.log(err3.message)})

注意:上述的代码无法保证文件的读取顺序,需要做进一步的改进!

.then() 方法的特性

如果上一个 .then() 方法中返回了一个新的 Promise 实例对象,则可以通过下一个 .then() 继续进行处理。通 过 .then() 方法的链式调用,就解决了回调地狱的问题。

2.3 基于 Promise 按顺序读取文件的内容

Promise 支持链式调用,从而来解决回调地狱的问题。示例代码如下:

import thenFs from 'then-fs'thenFs.readFile("./files/1.txt",'utf8') // 返回值是 promise 的实例对象。
.then(r1=>{   // 通过 .then 为第一个 Promise 实例指定成功之后的回调函数。console.log(r1)return thenFs.readFile("./files/2.txt",'utf8')  // 在第一个 .then 中返回一个新的 promise 的实例对象。
})
.then(r2=>{ // 继续调用 .then 为上一个 .then 的返回值(新的 Promise 实例) 指定成功之后的回调函数。console.log(r2)return thenFs.readFile("./files/3.txt",'utf8')  // 在第二个 .then 中返回一个新的 promise 的实例对象。
})
.then(r3=>{ // 继续调用 .then 为上一个 .then 的返回值(新的 Promise 实例) 指定成功之后的回调函数。console.log(r3)
})// 运行结果:
// txt file 1
// txt file 2
// txt file 3

2.4 通过 .catch 捕获错误

在 Promise 的链式操作中如果发生了错误,可以使用 Promise.prototype.catch 方法进行捕获和处理:

import thenFs from 'then-fs'thenFs.readFile("./files/10.txt",'utf8') // 文件.10txt 不存在导致读取失败,后面的 3 个 .then 都不执行。
.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)
})
.catch(err=>{console.log(err.message)
})// 运行结果:
// ENOENT: no such file or directory, open 'E:\study\es6\files\10.txt'

如果不希望前面的错误导致后续的 .then 无法正常执行,则可以将 .catch 的调用提前,示例代码如下:

import thenFs from 'then-fs'thenFs.readFile("./files/10.txt",'utf8') // 文件.10txt 不存在导致读取失败,后面的 3 个 .then 都不执行。
.catch(err=>{   // 捕获第一行发送的错误,并输出错误消息 console.log(err.message)
})
.then(r1=>{     // 由于 错误已经被及时处理,不影响后续 .then 的正常执行。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)
})// 运行结果:
// undefined
// txt file 2
// txt file 3

 2.5 Promise.all() 方法

Promise.all() 方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的 .then 操作(等待机制)。示例代码如下:

import thenFs from 'then-fs'// 定义一个数组,存放 3个文件读取的异步操作。
const promiseAll = [thenFs.readFile("./files/1.txt",'utf8'),thenFs.readFile("./files/2.txt",'utf8'),thenFs.readFile("./files/3.txt",'utf8')
]
// 将 Promise 的数组,作为 Promise.all() 的参数
Promise.all(promiseAll)
.then(([r1,r2,r3])=>{   // 所有文件读取成功(等待机制)console.log(r1,r2,r3)
})
.catch(err=>{  // 捕获 promise 异步操作中的 错误console.log(err.message)
})// 注意:数组中 Promise 实例的顺序,就是最终结果的顺序!
// 运行结果:
// txt file 1
// txt file 2
// txt file 3

2.6 Promise.race() 方法

Promise.race() 方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就立即执行下一步的 .then 操作(赛跑机制)。示例代码如下:

import thenFs from 'then-fs'
// 定义一个数组,存放 3个文件读取的异步操作。
const promiseAll = [thenFs.readFile("./files/1.txt",'utf8'),thenFs.readFile("./files/2.txt",'utf8'),thenFs.readFile("./files/3.txt",'utf8')
]// 将 Promise 的数组,作为 Promise.race() 的参数
Promise.race(promiseAll)
.then((result)=>{ // 只要任何一个异步操作完成,就立即执行下一步的 .then 操作(赛跑机制)。console.log(result)
})
.catch(err=>{  // 捕获 promise 异步操作中的 错误console.log(err.message)
})// 运行结果1:
// txt file 1// 运行结果2:
// txt file 3

三、基于 Promise 封装读文件的方法

方法的封装要求:

  • 方法的名称要定义为 getFile
  • 方法接收一个形参 fpath,表示要读取的文件的路径
  • 方法的返回值为 Promise 实例对象

import fs from "fs"function getFile(fpath){// 方法的返回值为  Promise 的实例对象// resolve : 调用 fetFiles() 方法时 通过 .then 指定‘成功的’回调函数。// reject  : 调用 fetFiles() 方法时 通过 .then 指定‘失败的’回调函数。return new Promise(function(resove,reject){fs.readFile(fpath,'utf8',(err,dataStr)=>{if(err) return reject(err)resove(dataStr)})})
}// getFile 方法的调用过程:
// getFile('./files/1.txt').then(成功的回调函数,失败的回调函数)
getFile('./files/1.txt').then((r1)=>{console.log(r1)},(error)=>{console.log(error.message)})
//也可以使用 catch 捕获失败信息
getFile('./files/1.txt').then((r1)=>{console.log(r1)}).catch((error)=>{console.log(error.message)})

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...