一.概念:
Promise对象用于表示一个异步操作最终完成(或失败)及其结果值。
二.学习的目的:
- 对异步操作的逻辑更清晰
- 了解axios函数内部的机制
- 能解决回调函数地狱问题
一个Promise对象一旦被创建出来就处于pending状态(待定),一旦执行异步任务,并且肯定会返回一个状态(即成功或失败)
如果成功,则执行 resolve () 函数,Promise对象状态变为fulfilled--已兑现,这时调用 .then(回调函数) 来执行异步任务成功的操作.
如果失败,则执行 reject () 函数Promise对象状态变为rejected--已拒绝,这时调用 .catch(回调函数) 来执行异步任务成功的操作.
并且Promise对象的状态一旦被改变(从pending-->>fulfilled 或者从 pending-->>rejected),它的状态就凝固了,不会再变了,这就是它的承诺(单词意思)。
具体代码简单实现:
<script>
// 1.创建Promise对象(pending-待定状态)
const p=new Promise((resolve,reject)=>
// 2.执行异步代码
setTimeout(()=>{
// resolve('模拟AJAX请求-成功结果')
reject(new Error('模拟AJAX请求-失败结果'))
},2000)
})
console.log(p)
// 3.获取结果
p.then(result =>{
console.log(result)
}).catch(error =>{
console.log(error)
})
</script>
三.回调函数地域问题
//获取省份
axios({ url:'/province')}.then(result => {
const pname = result.data.list[0]
//获取第一个省份默认下属的第一个城市名字
axios({ url: '/city', params: { pname}}).then(result =>{
const cname = result.data.list[0]
//获取第一个城市默认下属第一个地区名字
axios({ url: '/area', params: { pname.cname }}).then(result=> {
const area = result.data.list[0]
)}
)}
)}
如上面的例子获取一个省的一个城市的一个区,这样一层一层的请求,按正常写需要写成嵌套函数,像这样在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱问题。
缺点:可读性差,异常无法捕获,耦合性严重,牵一发而动全身。
四.Promise链式调用
axios({url:'/province'}).then(result =>{
pname = result.data.list[0]
//2.得到-获取城市Promise对象
return axios({url:'/city',params:{pname }
}).then(result =>{
const cname =result.data.list[0]
//3.得到-获取地区Promise对象
return axios({url:'/area', params:{ pname, cname }
}).then(result =>{
const areaName =result.data.list[0]
)}
在每个异步任务的 .then()回调函数中返回一个新的Promise异步任务,每一个返回的新Promis由后面的 .then() 来接受它的状态和结果,实现Promise链式调用,解决回调函数地狱问题。
不过这个方法并不好理解,所以推荐用后面的async,await。
五.async和await关键字
定义: async 函数是使用 async 关键字声明的函数。async 函数是 AsyncFunction 构造函数的实例,并且其中允许使用 await 关键字。async 和 await 关键字让我们可以用一种更简洁的方式写出基于 promise 的异步行为,而无需刻意地链式调用 promise 。
方法:在 async 函数内,使用 await 关键字取代 then 函数,等待获取 Promise 对象成功状态的结果值。
同样实现上面的例子:
// 1.定义async修饰函数
async function getData(){
//2.await等待Promise对象成功的结果
const pObj = await axios({url: '/province' })//获取省并等待结果后往下执行下一个
const pname = pobj.data.list[0]
const cObj= await axios({url:'/city',params:{ pname }})//获取城市
const cname= cObj.data.list[0]
const aObj = await axios({url:'/area',params{pname,cname}})//获取区
const areaName = a0bj.data.list[0]
}
//调用一下这个async函数
getData()
这样结构清晰,有可读性,好理解。
那怎么实现异常捕获呢:(只能借助try-catch)
把刚才的代码放到try-catch中:
// 1.定义async修饰函数
async function getData(){
try{
//2.await等待Promise对象成功的结果
const pObj = await axios({url: '/province' })//获取省并等待结果后往下执行下一个
const pname = pobj.data.list[0]
const cObj= await axios({url:'/city',params:{ pname }})//获取城市
const cname= cObj.data.list[0]
const aObj = await axios({url:'/area',params{pname,cname}})//获取区
const areaName = a0bj.data.list[0]
}catch(error){
console.dir(error)
}
}
//调用一下这个async函数
getData()
这个try-catch中的某个任务出错时,它下面的的代码便不会执行。