一、Promise对象
定义
- Promise是异步编程的一种解决方案,比传统的解决方案----回调函数和事件----更合理且更强大。所谓的Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个一步操作)的结果。从语法上来说,promise是一个对象,从他可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同种的方法进行处理。有了Promise对象就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
作用
- 有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易
二、 Promise的使用
- 生成promise对象,只需调用 Promise对象(),传入一个回调函数(resolve, reject) => {},这是用来让我们自定义什么时候发生状态的改变。
- 调用then()方法,传入两个回调函数,他们是用来定义Promise分别变成两种不同状态时应该执行怎样的业务逻辑
- 调用catch()方法,传入一个回调函数,定义当promise执行期间发生异常时应该执行怎样的业务逻辑,此时状态是reject。
let promise = new Promise((resolve,reject)=>{
console.log('11');
//setTimeout是异步执行的,后面的代码不用等里面的回调函数执行完后再执行
setTimeout(()=>{
console.log('22);
resolve('haha'); // 修改promise状态为 成功
},0)
console.log('33');
});
console.log('44');
// 参数从resolve,reject中传入,第一个函数是定义resolve的回调函数,第二个是定义reject的回调函数
// 定义成功或失败的具体执行方法
promise.then((data)=>{
//变成成功状态后自动执行
console.log(`${data},成功了!`)
},(error)=>{
//变成失败状态后自动执行
console.log(`${error},失败了!`);
})
// 当遇到异常或被reject时会调用
promise.catch((error) => {
console.log(`${error},异常了!`);
})
// 如果变成了reject状态拒绝(reject)和异常(catch)的方法都会被调用
// finally则无论变成什么状态都会执行
promise.finally(() => {
console.log(`定型啦!`)
})
总结:
从打印输出顺序可知道,Promise构造函数的同步阻塞式的,一调用,里面的代码就会执行。但是只是同步的代码会执行,异步的还是等最后再执行。
案例
读取a.txt文件,如果有内容,再读取b.txt文件,如果有内容,再读取c.txt文件,如果有内容,再读取d.txt文件
- 异步方式读取文件
fs.readFile('./files/a.txt',function(err,a){
if(!err){
fs.readFile('./files/b.txt',function(err,b){
if(!err){
fs.readFile('./files/c.txt',function(err,c){
if(!err){
fs.readFile('./files/d.txt',function(err,d){
if(!err){
console.log('1.'+d.toString());
}
})
}
})
}
})
}
})
// 注意观察上面的代码结构,层次非常深,特别不方便代理的阅读。我们将这样的代码结构称之为:回调地狱。
2.封装一个Promise对象,在里面读取第一个文件
new Promise(function(resolve,reject){
// resolve,用于返回正确的结果
// reject,用于返回错误信息
fs.readFile('./files/a.txt',function(err,a){
if(!err){
resolve(a.toString())
}
})
})
.then(function(r){
// 程序只能能进入到then,就表示之前的操作是成功,就要读取第二个文件;继续封装一个Promise对象,在里面读取第二个文件。
return new Promise(function(resolve){
fs.readFile('./files/b.txt',function(err,b){
if(!err){
resolve(b.toString())
}
})
})
})
.then(function(r){
return new Promise(function(resolve){
fs.readFile('./files/c.txt',function(err,c){
if(!err){
resolve(c.toString())
}
})
})
})
.then(function(r){
return new Promise(function(resolve){
fs.readFile('./files/d.txt',function(err,c){
if(!err){
resolve(c.toString())
}
})
})
})
.then(function(r){
console.log('2.'+r);
})
3.async关键字优化Promise对象
- 使用async异步函数,配合await异步等待,继续简化Promise的过程。
async function run(){
// 在异步函数中,通过await关键字获取,Promise对象里面的返回结果。
// await关键字的作用是异步等待,必须等到有返回结果,程序才会继续往下执行。
// await让异步代码,看上去像同步代码一样,其实本质上还是异步代码。
// 注意:await关键字,只能在async函数中使用。
await myRead('./files/a.txt')
await myRead('./files/b.txt')
await myRead('./files/c.txt')
let d = await myRead('./files/d.txt')
console.log('4.'+d);
}
run()
4.使用Promise编程,都会把公共的部分进行重新封装简写
new Promise(function(resolve,reject){
// resolve,用于返回正确的结果
// reject,用于返回错误信息
fs.readFile('./files/a.txt',function(err,a){
if(!err){
resolve(a.toString())
}
})
})
.then(function(r){
// 程序只能能进入到then,就表示之前的操作是成功,就要读取第二个文件;继续封装一个Promise对象,在里面读取第二个文件。
return new Promise(function(resolve){
fs.readFile('./files/b.txt',function(err,b){
if(!err){
resolve(b.toString())
}
})
})
})
.then(function(r){
return new Promise(function(resolve){
fs.readFile('./files/c.txt',function(err,c){
if(!err){
resolve(c.toString())
}
})
})
})
.then(function(r){
return new Promise(function(resolve){
fs.readFile('./files/d.txt',function(err,c){
if(!err){
resolve(c.toString())
}
})
})
})
.then(function(r){
console.log('2.'+r);
})