概述:
promise【承诺】是异步编程的一种解决方案,可以替代传统的解决方案—回调函数和事件,ES6统一了用法,并原生提供了Promise对象,promise是异步编程的一种解决方案。
什么时候我们会来处理异步事件呢?
一种很常见的场景就应该是网络请求了,我们封装一个网络请求的函数,因为不能立即拿到结果,所以不能像简单的1+1=2一样将结果返回所以我们往往会传入另外一个函数,在数据请求成功时,将数据通过传入的函数回调出去。 如果只是一个简单的网络请求,那么这种方案不会给我们带来很大的麻烦,但是当网络请求复杂是,就会出现回调地狱。
上面代码正常情况下,不会有什么问题,可以正常运行并且获取我们想要的结果,但是,这样的代码难看而且不容易维护【需要将后端打一顿】,我们更加希望的一种更加优雅的方式来进行这种异步操作。使用Promise,Promise可以以一种非常优雅的方式来解决这个问题。
定时器的异步事件
定时器调用异步事件例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//使用setTimeout
// setTimeout(()=>{
// console.log("Hello world!");
// },1000)
//参数->函数(resolve,rekect)
//resolve,reject本身它们又是函数
//链式编程
new Promise((resolve,reject) => {
//第一次网络请求
setTimeout(()=>{
resolve();
},1000)
}).then(()=>{
//第一次拿到结果的处理代码
console.log("Hello world!");
console.log("Hello world!");
console.log("Hello world!");
return new Promise((resolve,reject)=>{
//第二次网络请求的代码
setTimeout(()=>{
// resolve()
//失败时候调用reject
reject('error message')
},1000)
})
}).then(()=>{
//第二次处理的结果代码
console.log("Hello vue.js!");
console.log("Hello vue.js!");
console.log("Hello vue.js!");
return new Promise((resolve,reject)=>{
//第三次网络请求的代码
setTimeout(()=>{
resolve()
},1000)
})
}).then(()=>{
//第三次处理的代码
console.log("Hello Promise!");
console.log("Hello Promise!");
console.log("Hello Promise!");
}).catch((err)=>{
//
console.log(err);
})
// new -> 构造函数(1.保存了一些信息,2.传入的函数)
//在执行传入的回调函数时,会传入两个参数,resolve,reject,本身又是函数
</script>
</body>
</html>
效果:
简单来说,promise就是,你女朋就要过生日了,然后你承诺她在她的生日的时候会给她买一口红,好了你女朋友获得了你给她的承诺,但是,天知道这个承诺会不会实现,位置的因素很多,不能绝对认为你给你女朋友的promise就一定能实现。
所以Promise 有了三种可能的状态:
1.pending(待定的):你女朋友不知道你能不能给她口红,她只能等待她生日的时候的到来。等待状态,比如正在进行网络请求,或者定时器没有到时间。
2.fulfilled(已解决/以实现):到了生日那天你真的给你女朋友一支口红,你实现了你女朋友的承诺。满足状态,当我们主动回调了resolve的时候,就处于该状态,并且回调.then()。
3.rejected(已拒绝/没有实现):你忘了你女朋友的生日,所以没有送口红给你女朋友。拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()。
例子
<script>
new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('hellow vue.js')
//reject("error message")
},1000)
//调用resolve的时候执行函数1,调用reject的时候执行函数2
}).then(data =>{
console.log(data);
},err=>{
console.log(err);
})
</script>
执行reslove的时候调用than里面的函数1,执行reject的时候执行函数2
Promise的链式调用
在我们看到promise的流程图的时候,发现无论是then还是catch都可以返回一个Promise对象,所以promise代码可以进行链式调用,我们直接通过promise包装了一下数据,将promise对象返回了
Promise.resolve():将数据包装成promise对象,并且在内部回调resolve()函数。
Promise.reject():将数据包装成promise对象,并且在内部回调reject()函数。
三层处理链式调用例子
<script>
//网络请求:aaa -> 自己处理(10行)
//处理:aaa111 -> 自己处理(10行)
//处理:aaa111222-> 自己处理
new Promise((resolve,reject)=>{
setTimeout(() => {
resolve("aaa");
},1000)
}).then(res => {
//1.自己处理10行代码
console.log(res,"第一层的10行处理代码");
//2.对结果进行第一次处理
return new Promise((resolve)=>{
resolve(res+'111')
})
}).then(res =>{
console.log(res,"第二层10行处理代码");
return new Promise(resolve=>{
resolve(res+'222')
})
}).then(res=>{
console.log(res,"第三层的10行处理代码")
})
</script>
其中than返回的直接是一个promise对象,不需要重新new promise对象,简写方法如下:
<script>
//网络请求:aaa -> 自己处理(10行)
//处理:aaa111 -> 自己处理(10行)
//处理:aaa111222-> 自己处理
new Promise((resolve,reject)=>{
setTimeout(() => {
resolve("aaa");
},1000)
}).then(res => {
//1.自己处理10行代码
console.log(res,"第一层的10行处理代码");
//2.对结果进行第一次处理
return Promise.resolve(res+'111')
}).then(res =>{
console.log(res,"第二层10行处理代码");
return Promise.resolve(res+'222')
}).then(res=>{
console.log(res,"第三层的10行处理代码")
})
</script>
更简洁的写法,直接将结果return ,到时候then内部将会对promise进行包装,直接省略return.promise写法
<script>
//网络请求:aaa -> 自己处理(10行)
//处理:aaa111 -> 自己处理(10行)
//处理:aaa111222-> 自己处理
new Promise((resolve,reject)=>{
setTimeout(() => {
resolve("aaa");
},1000)
}).then(res => {
//1.自己处理10行代码
console.log(res,"第一层的10行处理代码");
//2.对结果进行第一次处理
return res+'111'
}).then(res =>{
console.log(res,"第二层10行处理代码");
return res+'222'
}).then(res=>{
console.log(res,"第三层的10行处理代码")
})
</script>
代码效果:
如果有一层reject的时候的写法:
<script>
//网络请求:aaa -> 自己处理(10行)
//处理:aaa111 -> 自己处理(10行)
//处理:aaa111222-> 自己处理
new Promise((resolve,reject)=>{
setTimeout(() => {
resolve("aaa");
},1000)
}).then(res => {
//1.自己处理10行代码
console.log(res,"第一层的10行处理代码");
//2.对结果进行第一次处理
return Promise.reject("err")
}).then(res =>{
console.log(res,"第二层10行处理代码");
return res+'222'
}).then(res=>{
console.log(res,"第三层的10行处理代码")
}).catch(err => {
console.log(err);
})
</script>
最简洁的报错写法 throw语句,直接throw 'error message’
<script>
//网络请求:aaa -> 自己处理(10行)
//处理:aaa111 -> 自己处理(10行)
//处理:aaa111222-> 自己处理
new Promise((resolve,reject)=>{
setTimeout(() => {
resolve("aaa");
},1000)
}).then(res => {
//1.自己处理10行代码
console.log(res,"第一层的10行处理代码");
//2.对结果进行第一次处理
throw 'error message'
}).then(res =>{
console.log(res,"第二层10行处理代码");
return res+'222'
}).then(res=>{
console.log(res,"第三层的10行处理代码")
}).catch(err => {
console.log(err);
})
</script>
效果:
Promise - all方法使用
Promise.all是在所有的Promise对象都执行完成之后resolve。参数是一个数组,数组的每一项都是一个Promise对象就可以。
什么情况下使用呢?
当有一个需求,必须两个结果都拿到手才进行下一步操作的时候使用!
如上代码通过改变两个变量判断一个需求中的两个状态是否完成,显得很繁琐,promise直接包装两个异步请求,它可以在两个异步请求都完成得时候在一个地方进行回调!
格式:
Promise.all(结果,数组可迭代对象)
使用setTimeout进行模拟:
<script>
//Promise.all(结果,数组可迭代对象)
Promise.all([
new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve({name:"wuyong",age:18});
},2000)
}),
new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("resolve2");
},1000)
})
]).then(results =>{
console.log(results);
})
</script>
显示结果:
完结~