前言
之前一直没有专门的去学过promise,只知道它可以用来解决'回调地狱',是异步的一种实践方式。最近在项目中遇到无痛感刷新token时,要用到promise的特性,故在此记录下学习历程。
promise解决的问题
关于异步使用的最多的就是发送ajax请求后台数据,当一个页面不止一个请求且请求有先后关系时,就会遇到"回调地狱"的问题,在不使用async+await的情况下,我们通常会写出类似下面的代码
this.$axios.post(url,{}).then(res=>{
if(res.data.code==200){
this.$axios.post(url,{id:res.data.id}).then(resp=>{
if(resp.data.code==200){
console.log('接口请求完成')
}
})
}
})
坦然,当请求的接口无限堆砌的时候,我们的代码会变得臃肿和难以阅读,当遇到bug我们很难直接进行定位,这不利于高效开发和代码维护,也不利于协同开发。
使用promise改写
let p1 = new Promise((resolve,reject)=>{
this.$axios.post(url,{}){
if(res.data.code==200){
resolve({id:res.data.id})
}
}
})
let p2 = new Promise((resolve,reject)=>{
resolve(p1)
})
p2.then(res=>{
this.$axios.post(url,{id:res.id}).then(resp=>{
console.log('接口请求完成')
})
})
从视觉上看,我们将两次请求进行分开,结构更加清晰
promise语法
1-promise实例
let p = new Promise((resolve,reject)=>{//使用new操作符实例化promise,会返回一个promise对象
resolve() //发出成功通知
reject()//发出失败通知
}).then() //then方法相当于一个拦截器,允许我们获取resolve或者reject抛出的值,如果为空,则会向下一个 then传递
.then(success=>{//接受resolve通知
},error=>{//接受reject发出的通知
})
2-特殊点--新promise实例必须抛出状态而then(finally、catch)方法返回的promise默认抛出resolve
let p = new Promise((resolve,reject)=>{
//如果不手动抛出状态那么打印p的结果为pending
reject('出错了,请联系管理员')
})
let p2 = p.then(null,err=>{
console.log(err) //通过.then拦截抛出状态,这里得到'出错了,请联系管理员'
})
let p3 = p2.then(ok=>{ //p2是p通过then返回的promise,会默认抛出resolve,因此将打印'ok'
console.log('ok')
return new Promise((resolve,reject)=>{ //如果想控制抛出状态,那么我们可以在then中return一个新的 promise
reject('阿哦,出错了~')
})
},error=>{
console.log('error')
})
p3.then(null,reason=>{
console.log(reason) //这里的p3是一个新的promise,因此将根据抛出状态进行捕获
})
3-异常处理
new Promise((resolve,reject)=>{
//抛出错误
reject('err msg')
//或者
throw new Error('err msg')
}).then(null,err=>{//如果只有一个promise我们可以将then的第二个参数当作异常捕获的回调
}).catch(err=>{//当存在链式promise时,我们可以使用catch来统一捕获异常并处理
})
4-异步后处理
new Promise((resolve,reject)=>{
reject('err')
}).catch(err=>{}).finally(()=>{
//这里类似jquery中ajax请求的complete,我们可以在这里关闭一个loading动画
})
5-resolve/reject的妙用
let data = null,
pre_id = '上一个接口数据';
function getData(){
//缓存
if(data){
//由于外部使用了promise语法获取函数返回值,因此不能直接return data
return Promise.resolve(data)
}
if(!pre_id){
return Promise.reject('接口缺少请求参数')
}
return new Promise((resolve,reject)=>{
this.$axios.get(url,{pre_id}).then(res=>{
data = res.data
resolve(data)
})
})
.then(res=>{
return res
})
.catch(err=>{})
.finally(()=>{})
}
setInterval(()=>{
getData().then(res=>console.log(res)).catch(err=>{})
},1000)
6-批量执行promise
let p1 = new Promise((resolve,reject)=>{})
.catch(err=>{})//如果p1单独进行了错误处理,那么all方法将无法监听到p1的resolve,all得到的是catch返回的 promise,有默认的resolve
let p2 = new Promise((resolve,reject)=>{})
Promise.all([p1,p2]) //我们只需要给all方法传递一个由promise组成的数组,Promise就会批量进行调用
.then(res=>{ //这里的成功必须是p1和p2都抛出resolve状态,否则将走catch接口
}).catch(err=>{})
7-更松散的批量执行之allSettled
代码同6,在Promise.allSettled([p1,p2]).then(res=>{})//不强制p1p2均为resolve,永远不会走catch接口
8-龟兔赛跑之-race
let p1 = new Promise((resolve, reject) => {
setTimeout(()=>{
reject('网络错误')
},180)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('ok')
})
})
Promise.race([p1,p2]).then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
以上就是promise的语法内容
我们学习任何事物都是一次从无到有、从走到跑的过程,只有了解其存在的语法,才能在实战中运用起来,大家加油
(promise实战部分可以参考这个哦:https://www.jianshu.com/p/e107b454bf20)
网友评论