Promise
Promise
回调地狱
多层回调函数的相互嵌套,就形成了回调地狱。示例代码如下:
复制setTimeout(() => { // 第 1 层回调函数
console.log('延时 1 秒后输出')
setTimeout(() => { // 第 2 层回调函数
console.log('再延时 2 秒后输出')
setTimeout(() => { // 第 3 层回调函数
console.log('再延时 3 秒后输出') }, 3000)
}, 2000) }, 1000)
- 回调地狱的缺点:
⚫ 代码耦合性太强,牵一发而动全身,难以维护
⚫ 大量冗余的代码相互嵌套,代码的可读性变差
为了解决回调地狱的问题,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() 方法时,成功的回调函数是必选的、失败的回调函数是可选的
基于 then-fs 读取文件内容
由于 node.js 官方提供的 fs 模块仅支持以回调函数的方式读取文件,不支持 Promise 的调用方式。因此,需要先运行如下的命令,安装 then-fs 这个第三方包,从而支持我们基于 Promise 的方式读取文件的内容npm i then-fs
- then-fs 提供的 readFile() 方法,可以异步地读取文件的内容,它的返回值是 Promise 的实例对象。因此可以调用 .then() 方法为每个 Promise 异步操作指定成功和失败之后的回调函数。示例代码如下:
复制import thenFs from 'then-fs'
// 注意:.then()中的失败回调是可选的,可以被省略
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() 方法中返回了一个新的 Promise 实例对象,则可以通过下一个 .then() 继续进行处理。通过 .then() 方法的链式调用,就解决了回调地狱的问题
基于 Promise 按顺序读取文件的内容
复制//Promise 支持链式调用,从而来解决回调地狱的问题
thenFs.readFile('./files/1.txt','utf8')
// 1.返回值是 Promise 的实例对象
.then((r1) => {
// 2. 通过.then 为第一个 Promise 实例指定成功之后的回调函数
console.log(r1)
return thenFs.readFile('./files/2.txt','utf8')
// 3.在第一个.then 中返回一个新的 Promise 实例对象
})
.then((r2)=> {
// 4.继续调用.then,为上一个.then 的返回值(新的 Promise 实例)指定成功之后的回调函数
console.log(r2)
return thenFs.readFile('./files/3.txt', 'utf8')
// 5.在第二个.then 中再返回一个新的 Promise 实例对象
})
.then((r3) => {
// 6. 继续调用.then,为上一个.then 的返回值(新的 Promise 实例)指定成功之后的回调函数
console.log(r3)
})
通过 .catch 捕获错误
在 Promise 的链式操作中如果发生了错误,可以使用 Promise.prototype.catch 方法进行捕获和处理
- 如果不希望前面的错误导致后续的 .then 无法正常执行,则可以将 .catch 的调用提前
复制thenFs.readFile('./files/11.txt', 'utf8') .catch(err=>{
// 捕获第 1 行发生的错误,并输出错误的消息
console.log(err.message)
// 由于错误已被及时处理,不影响后续.then 的正常执行
})
.then(r1=>{
console.log(r1)
// 输出 undefined
return thenFs.readFile('./files/2.txt', 'utf8') })
.then(r2=>{
console.log(r2)
// 输出 222
return thenFs.readFile('./files/3.txt', 'utf8') })
.then(r3=>{
console.log(r3)
// 输出 333 })
Promise.all() 方法
Promise.all() 方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的 .then 操作(等待机制)
复制//注意:数组中 Promise 实例的顺序,就是最终结果的顺序
//1.定义一个数组,存放3个读文件的异步操作
const promiseArr =[
thenFs.readFile('./files/1.txt', 'utf8'),
thenFs.readFile('./files/2.txt', 'utf8'),
thenFs.readFile('./files/3.txt', 'utf8'),
]
//2.将 Promise 的数组,作为 Promise.all()的参数
Promise.all(promiseArr)
.then(([r1,r2,r3])=>{
// 2.1 所有文件读取成功(等待机制)
console.log(r1,r2,r3)
})
.catch(err=>{
// 2.2 捕获 Promise 异步操作中的错误
console.log(err.message)
})
Promise.race() 方法
Promise.race() 方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就立即执行下一步的.then 操作(赛跑机制)
复制//1.定义一个数组,存放3个读文件的异步操作
econst promiseArr = [
thenFs.readFile('./files/1.txt', 'utf8'),
thenFs.readFile('./files/2.txt', 'utf8'),
thenFs.readFile('./files/3.txt', 'utf8'),
]
//2.将Promise 的数组,作为Promise.race()的参数
Promise.race(promiseArr)
.then((result) => {
// 2.1 只要任何一个异步操作完成,就立即执行成功的回调函数(赛跑机制)console.log(result)
})
.catch(err => (
// 2.2 捕获 Promise 异步操作中的错误
console.log(err.message)
})
基于 Promise 封装读文件的方法
- 想要创建具体的异步操作,则需要在 new Promise() 构造函数期间,传递一个 function 函数,将具体的异步操作定义到 function 函数内部
- 通过 .then() 指定的成功和失败的回调函数,可以在 function 的形参中进行接收
- 调用 resolve 和 reject 回调函数
复制function getFile(fpath){
// resolve 是“成功的”回调函数;reject 是“失败的”回调函数
fs.readFile(fpath, 'utf8', (err, dataStr)=> {
return new Promise(function(resolve, reject) {
if(err) return reject(err)
// 如果读取失败,则调用“失败的回调函数”
resolve(dataStr)
// 如果读取成功,则调用“成功的回调函数”
})
})
}
//getFile 方法的调用过程:
getFile('./files/1.txt').then(成功的回调函数,失败的回调函数)
本文来自博客园,作者:starking_front-end,转载请注明原文链接:https://www.cnblogs.com/starking-985/p/15894570.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?