1.为什么要使用Promise
为了解决回调地狱问题,ES6引入了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=>{},err=>{})
- 调用.then()方法时,成功的回调函数是必选的,失败的回调函数是可选的
3.Promise的基本使用
3.1 基于回调函数按顺序读取文件内容
之前的方法
// 读取文件内容
const fs=require("fs");
// 读取文件内容1.txt
fs.readFile("./files/1.txt","utf8",(err,res)=>{
if(err) return console.log("读取文件内容失败!"+err.message);
console.log("1.txt的内容为:",res);
fs.readFile("./files/2.txt","utf8",(err,res)=>{
if(err) return console.log("读取文件内容失败!"+err.message);
console.log("2.txt的内容为:",res);
fs.readFile("./files/3.txt","utf8",(err,res)=>{
if(err) return console.log("读取文件内容失败!"+err.message);
console.log("3.txt的内容为:",res);
})
})
})
3.2 基于then-fs读取文件内容
由于node.js官方提供的fs模块仅支持以回调函数的方式读取文件,不支持Promise的调用方式。因此,需要先运行如下的命令,安装then-fs这个第三方包,从而支持我们基于Promise的方式读取文件的内容。
npm install then-fs
3.2.1 then-fs的基本使用
调用then.fs提供的readFile()方法,可以异步读取文件的内容,它的返回值是Promise的实例对象。因此可以调用.then()方法为每个Promise异步操作指定成功和失败之后的回调函数。失败的回调函数可以被省略。
// 导入then-fs模块
import thenFS from 'then-fs';
thenFS.readFile("./files/1.txt","utf8").then(res=>{console.log(res);},err=>{console.log(err.message);})
thenFS.readFile("./files/2.txt","utf8").then(res=>{console.log(res);},err=>{console.log(err.message);})
thenFS.readFile("./files/3.txt","utf8").then(res=>{console.log(res);},err=>{console.log(err.message);})
- 以上操作虽然能执行成功,但是无法保证执行的顺序
3.3then()方法的特性
如果上一个.then()方法中返回一个新Promise实例对象,则可以通过下一个.then()继续进行处理,通过.then()的链式调用,就解决了回调地狱的问题
3.4 基于Promise按顺序读取文件的内容
import thenFs from "then-fs";
thenFs.readFile("./files/1.txt","utf8").then(res=>{
console.log(res);
return thenFs.readFile("./files/2.txt","utf8");
}).then(res=>{
console.log(res);
return thenFs.readFile("./files/3.txt","utf8");
}).then(res=>{
console.log(res);
})
3.5 通过catch来捕获错误
在Promise的链式调用中如果发生了错误,可以使用Promise.prototype.catch方法进行捕获和处理:
- 如果在链式调用中发生错误了,不会执行后面的链式调用,直接到最后的catch方法捕获
import thenFs from "then-fs";
// 在Promise的链式调用中如果发生了错误,可以通过Promise.prototype.catch来捕获错误
// 一般在最后进行捕获错误
thenFs.readFile("./files/1.txt","utf8").then(res=>{
console.log(res);
return thenFs.readFile("./files/2.txt","utf8");
}).then(res=>{
console.log(res);
return thenFs.readFile("./files/3.txt","utf8");
}).then(res=>{
console.log(res);
}).catch(err=>{
console.log("err:",err.message);
})
- 如果不希望前面的错误导致后续的.then正常执行,则可以将.catch方法提前调用,如下:
import thenFs from "then-fs";
// 在Promise的链式调用中如果发生了错误,可以通过Promise.prototype.catch来捕获错误
// 一般在最后进行捕获错误
// 如果不想前面的错误影响后面代码的正常运行,可以将.catch提前
thenFs.readFile("./files/11.txt","utf8").catch(err=>{
console.log("err:",err.message);
})
.then(res=>{
console.log(res);
return thenFs.readFile("./files/2.txt","utf8");
}).then(res=>{
console.log(res);
return thenFs.readFile("./files/3.txt","utf8");
}).then(res=>{
console.log(res);
})
3.5 Promise.all()方法 【等待机制】
Promise.all()方法会发起并行的Promise异步操作,等所有的异步操作全部结束后才会执行下一步.then操作(等待机制)。示例代码如下:
// Promise.all方法会发起并行的异步操作请求,它会等所有的异步请求操作完成后,继续执行一个.then操作(等待机制)
import thenFs from "then-fs";
// 定义一个数组,用于存放3个读文件的异步操作
const req=[
thenFs.readFile("./files/1.txt","utf8"),
thenFs.readFile("./files/2.txt","utf8"),
thenFs.readFile("./files/3.txt","utf8"),
]
// 将定义的异步请求操作数组作为参数传入
Promise.all(req).then(([r1,r2,r3])=>{
console.log(r1,r2,r3);//111 222 333
}).catch(err=>{
console.log("err:",err.message);
})
- 注意:数组中Promise实例的顺序,就是拿结果的顺序
3.6 Promise.race() [赛跑机制]
Promise.race()方法可以发起并行的异步请求操作,只要任何一个异步操作完成后,就会执行后面.then操作(赛跑机制)。
// 导入
import thenFs from "then-fs";
// 创建一个异步操作的数组
const req=[
thenFs.readFile("./files/1.txt","utf8"),
thenFs.readFile("./files/2.txt","utf8"),
thenFs.readFile("./files/3.txt","utf8"),
]
// 执行Promise.race()方法,它可以发起并行的异步请求操作,任何一个操作完成后,就会执行后面的.then方法(赛跑机制)
Promise.race(req).then(res=>{
console.log("res:",res);
}).catch(err=>{
console.log("err:",err);
})
3.7 基于Promise封装读取文件的方法
- 定义一个方法为getFile
- 它有一个形参是fPath:表示文件的路径
- 它的返回值是一个Promise对象
function getFile(fPath){
return new Promise()
}
- 注意:这个new Promise()只是创建了一个形式上的异步操作
3.7.1 获取.then的两个实参
通过.then()指定成功和失败的回调函数,可以在function中形参进行接收,示例代码如下:
function getFile(fPath){
return Promise(function(resolve,reject){
fs.readFile(fPath,"utf8",(err,res)=>{})
})
}
getFile('./files/1.txt').then(成功的回调函数,错误的回调函数) //成功的回调函数对应形参的resolve,失败的回调函数对应上面的reject
3.7.2 调用resolve和reject回调函数
Promise的异步操作的结果,可以调用resolve或reject回调函数进行处理。示例代码如下:
function getFile(fPath){
return Promise(function(resolve,reject){
fs.readFile(fPath,"utf8",(err,res)=>{
if(err) reject(err);//执行失败
resolve(res);//执行成功
})
})
}
getFile('./files/1.txt').then(成功的回调函数,错误的回调函数) //成功的回调函数对应形参的resolve,失败的回调函数对应上面的reject
例如:
// 导入
import fs from "fs";
function getFile(fPath){
return new Promise(function(resolve,reject){
return fs.readFile(fPath,"utf8",(err,res)=>{
if(err) reject(err)
resolve(res);
})
})
}
getFile("./files/1.txt").then(res=>{console.log("res:",res);},err=>{console.log("err:",err);})
4.总结

网友评论