JS利用async、await处理少见的登录业务逻辑
在用uniapp开发一个项目时,有这样一个需求:用户首次登录后,uniapp自动保存用户名密码,之后不管是再次打开项目(打开项目时登录状态已失效)还是 请求接口(接口返回登录失效)时,都会先自动默认的登录,然后再进行之后的操作。
比如页面需要调用功能接口1、2,但是必须是登录状态。如下图所示:
根据图中的逻辑流程可以断定共有 登录接口、功能接口1、功能接口2 三个request请求,我们抛开要跳转登录页的情况下,那么打开页面会有两种需要特殊处理的情况:
1.没有登录状态,程序默认调用已存的用户名和密码去调用登录接口,接口登录成功后再继续调用功能接口1和2。
2.页面已存在登录状态(比如vuex判断是否登录),但是调用接口1或者2时返回需要登录的状态(可能页面停留时间过久,服务器保存的登录状态已失效),这时需要跳到第一种情况去执行。
根据上述的两种情况,我们常见的解决办法就是
1 //页面执行 2 if(!loginStatus){//页面判断是否登录 3 login(); 4 }else{ 5 server(); 6 } 7 //假如server中的catch为接口返回登录失效,需要重新登录 8 function server(){ 9 10 server1Promise().then(()=>{ 11 }).catch(()=>{ 12 login(); 13 }) 14 server2Promise().then(()=>{ 15 }).catch(()=>{ 16 login(); 17 }) 18 } 19 function login(){ 20 loginPromise().then(()=>{ 21 server(); 22 }) 23 }
这样会有很多问题,比如 无法分开调用接口1、接口2(有时候页面逻辑会需要分开调用); 同时调用接口1和2,都返回需要登录状态时,会重复去请求登录接口,进而重复请求接口1和2。
那么就需要另一种解决方法能同时解决这个问题!
/// request.js const request = (data,url) = >{ return new Promise((s,f)=>{ uni.request({//也可以是其他的接口请求 complete(r){ if(r.statusCode == 200) s(r); else f(r); }, url:url,data:data }) }) } let isLogin =false;//是否正在登录 let loginStatus = async function () { return true}();//登录结果,默认可以登录 const _req = async (_d,_u)=>{ return new Promise((s,f)=>{ let _let_go = await loginStatus.catch(()=>{return false;}); if(_let_go){ request(_d,_u).then((r)=>{ s(r)//接口返回正常 }).catch(()=>{ //假使catch是调用业务接口返回要登录 autoLogin();//自动登录 let _let_go_n = await loginStatus.catch(()=>{return false;}); if(_let_go_n){ request(_d,_u).then((r)=>{ s(r)}).catch(()=>{ f({status:0,msg:'请登录'}) }) //再次请求,如果还是失败就不再继续 }else{ f({status:0,msg:'请登录'})} }) }else{ //已经调用了登录接口,还是失败,那么跳转到登录页 f({status:0,msg:'请登录'}) } }); } //自动登录 const autoLogin = ()=>{ if(isLogin ){return} var _f = ()=>{ isLogin =true; return new Promise((s, f) => { var userinfo= uni.getStorageSync('userinfo');//读取保存的用户名密码 if(userinfo){ request(userinfo,'login').then(()=>{isLogin =false;s(true)}).catch(()=>{isLogin =false;s(false)}); }else{isLogin =false;s(false)} }) } loginStatus = _f(); }
//业务接口
const server1 = (_d)=>{
return _req(_d,'server1')
}
const server2 = (_d)=>{
return _req(_d,'server2')
}
//登录接口,登录接口要和autoLogin分开,在login成功后要保存用户名和密码
const login = (_d)=>{ ... }
export default {server1,server2,login }
/// page.vue
import request from 'request.js'
...
业务逻辑
...
request.server1().then()
...
业务逻辑
...
request.server2().then()