Promise基本使用
1. Promise的基本概念
- Promise是一个构造函数
- 我们可以创建Promise的实例 const p =new Promise()
- new 出来的Promise实例对象,代表一个异步操作
- Promise.prototype上包含一个.then()方法
- 每一次new Promise()构造函数得到的实例对象都可以通过原型链的方式访问到.then()方法,例如p.then()
- .then()方法可以预先指定成功和失败的回调函数
- p.then(成功的回调函数,失败的回调函数)
- p.then(result=>{},error=>{})
- 调用回调函数时,成功的回调是必选的,失败的回调是可选的
2. 基于then-fs读取文件内容
由于node.js官方提供的fs模块仅支持以回调函数的方式读取文件,不支持Promise的调用方式。因此,需要先安装
then-fs第三方包,从而支持我们基于Promise的方式读取文件内容
运行如下命令下载then-fs包
npm i then-fs
下载安装完成后调用then-fs提供的readFile()方法,可以异步地读取文件的内容,它的返回值是Promise的实例对象。因此可以调用.then()方法为每个Promise异步操作指定成功和失败后的回调函数。示例代码如下:
import thenFs from 'then-fs'
thenFs.readFile('./Promise/files/1.txt','utf8').then(r1=>{console.log(r1)},err1=>{console.log(err1.message)})
thenFs.readFile('./Promise/files/2.txt','utf8').then(r2=>{console.log(r2)},err2=>{console.log(err2.message)})
thenFs.readFile('./Promise/files/3.txt','utf8').then(r3=>{console.log(r3)},err3=>{console.log(err3.message)})
结果如下:
正常顺序是“111,222,333”,可见异步调用无法保证读取文件顺序
如果要保证读取顺序,则通过如下代码实现,同时解决了回调地狱问题
thenFs.readFile('./Promise/files/1.txt','utf8')
.then(r1=>{
console.log(r1)
return thenFs.readFile('./Promise/files/2.txt','utf8')
})
.then(r2=>{
console.log(r2)
return thenFs.readFile('./Promise/files/3.txt','utf8')
})
.then(r3=>{
console.log(r3)
})
3. Promise.all()方法
Promise.all()方法会发起并行的Promise异步操作,等所有的异步操作全部结束后才会执行下一步的.then操作(等待机制)。
示例代码如下:
onst promiseArr = [
thenFs.readFile('./Promise/files/1.txt','utf8'),
thenFs.readFile('./Promise/files/2.txt','utf8'),
thenFs.readFile('./Promise/files/3.txt','utf8')
]
Promise.all(promiseArr)
.then(([r1,r2,r3])=>{
console.log(r1,r2,r3)
})
.catch((err)=>{
console.log(err.message)
})
打印结果顺序和数组声明顺序相同
4. Promise.race()方法
race()方法就是赛跑机制的实现,即只要有一个promsie执行完成后就立刻执行.then()操作(赛跑机制)
const promiseArr = [
thenFs.readFile('./Promise/files/1.txt','utf8'),
thenFs.readFile('./Promise/files/2.txt','utf8'),
thenFs.readFile('./Promise/files/3.txt','utf8')
]
Promise.race(promiseArr)
.then((res=>{
console.log(res)
}))
.catch((err)=>{
console.log(err.message)
})
打印结果是111,222,333中的任意一个.
4. 创建自定义异步操作
import thenFs from "fs";
function getFile(fpath){
return new Promise(function(resolve,reject){
thenFs.readFile(fpath, 'utf8', (err,dataStr)=>{
if(err)return reject(err)
resolve(dataStr)
})
})
}
getFile('./Promise/files/1.txt').then(success=>{
console.log(success)
},error=>{
console.log(error)
})
success回调函数对应于resolve,error回调函数对应于reject
运行结果如图:
5. async/await
async/await是ES8引入的新语法,用来简化Promise异步操作。在async/await出现之前,开发者只能通过链式.then()的方式
处理Promise异步操作。
- .then链式调用的优点:解决了回调地狱的问题
- .then链式调用的缺点:代码冗余、阅读性差、不易理解
import thenFs from "then-fs";
async function getAllFile(){
const r1 = await thenFs.readFile('./Promise/files/1.txt','utf8');
console.log(r1)
}
getAllFile()
aysnc和await必须搭配使用,这样就可以避免用.then()方式调用
async/await使用注意事项
- 如果在function中使用了await,则function必须被async修饰
- 在async方法中,第一个await之前的代码会同步执行,await之后的代码会异步执行
如:
import thenFs from "then-fs";
console.log('A')
async function getAllFile(){
console.log('B')
const r1 = await thenFs.readFile('./Promise/files/1.txt','utf8');
console.log(r1)
const r2 = await thenFs.readFile('./Promise/files/2.txt','utf8');
console.log(r2)
const r3 = await thenFs.readFile('./Promise/files/3.txt','utf8');
console.log(r3)
}
getAllFile()
console.log('C')
在这里主线程打印‘B’碰到await后便开启另一个线程,于是主线程接着打印‘C’,等await方法执行完后打印r1,r2,r3