uni-app 中实现 onLaunch 异步回调后执行 onLoad 最佳实践
前言
好久没写博客了,由于公司业务需要,最近接触uiapp比较多,一直想着输出一些相关的文章。正好最近时间富余,有机会来一波输出了。
问题描述
在使用 uni-app 开发项目时,会遇到需要在 onLaunch 中请求接口返回结果,并且此结果在项目各个页面的 onLoad 中都有可能使用到的需求,比如微信小程序在 onLaunch 中进行登录后取得 openid 并获得 token,项目各页面需要带上该 token 请求其他接口。
问题原因
在onLaunch 中的请求是异步的,也就是说在执行 onLaunch 后页面 onLoad 就开始执行了,而不会等待 onLaunch 异步返回数据后再执行,这就导致了页面无法拿到 onLaunch 中异步获取的数据。
解决问题
知道问题原因之后,解决起来就容易了。作为资深白嫖党,先是搜索了相关资料,发现了下面的解决方案。
解决方案一
既然在onLaunch中请求是异步的原因导致这个问题,那改成同步的不就行了,这里利用Promise来解决这个问题。步骤如下。
步骤一
在 main.js 中增加如下代码:
Vue.prototype.$onLaunched = new Promise(resolve => {
Vue.prototype.$isResolve = resolve
})
步骤二
在 App.vue 的 onLaunch
中增加代码 this.$isResolve()
,具体如下:
onLaunch () {
uni.login({
provider: 'weixin',
success: loginRes => {
login({ // 该接口为我们自己写的获取 openid/token 的接口,请替换成自己的
code: loginRes.code
}).then(res => {
try {
console.info(res.data.token)
uni.setStorageSync('token', res.data.token)
this.$isResolve()
} catch (e) {
console.error(e)
}
})
}
})
}
步骤三
在页面 onLoad
中增加代码 await this.$onLaunched
,具体如下:
async onLoad(option) {
await this.$onLaunched
let token = ''
try {
token = uni.getStorageSync('token')
} catch(e) {
console.error(e)
}
// 下面就可以使用 token 调用其他相关接口
}
有了这个解决方案,我就开始在实际项目中是用来了。但随着项目的复杂度增加,发现这个方案使用起来有一些弊端。每个页面都需要在 onLoad
中增加代码代码也太烦人了。
有没有更优雅的方案呢?继续查找资料,有个解决方案是定制一个页面钩子,然后注册全局的异步任务,定义钩子的触发条件,满足条件时即可自动执行页面里相关的钩子。相关方案见参考资料2。
但这个方案我也不太满意,仍然需要在页面添加一些函数去响应请求。后面突然想到,可以监听路由变动,在路由跳转之前完成请求。
解决方案二(推荐)
正好项目中用到了uni-simple-router插件,提供了全局前置守卫事件beforeEach
,其本质是代理了所有的生命周期,让生命周期更加可控,这样就可以很好的解决我们面临的问题了。步骤如下:
步骤一
在 route.js 增加如下代码:
// 登录(可放在公共函数里面)
const login = () => {
return new Promise(function(resolve, reject) {
uni.login({
provider: 'weixin',
success: loginRes => {
login({ // 该接口为我们自己写的获取 openid/token 的接口,请替换成自己的
code: loginRes.code
}).then(res => {
resolve(res);
}, err => {
reject(err);
})
},
fail: err => {
reject(err);
}
});
});
}
// 获取token(可放在公共函数里面)
const getToken = () => {
let token = ''
try {
token = uni.getStorageSync('token')
} catch(e) {
console.error(e)
}
return token;
}
// 是否登录
let hasLogin = false;
router.beforeEach(async (to, from, next) => {
// 首次进来,没有登录并且token不存在先请求数据
if(!hasLogin&&!getToken()){
const res = await login();
try {
console.info(res.data.token)
uni.setStorageSync('token', res.data.token)
hasLogin = true
} catch (e) {
console.error(e)
}
}
next()
})
步骤二
在页面 onLoad
中直接就可以获取 token
并使用,具体如下:
onLoad(option) {
let token = ''
try {
token = uni.getStorageSync('token')
} catch(e) {
console.error(e)
}
// 下面就可以使用 token 调用其他相关接口
}
这个解决方案就灵活很多,只需要在 route.js 中写入代码,其他任意地方都可以调用。不用担心新增页面忘记相关方法的引入,更加灵活自由。
由于这个解决方案基于uni-simple-router插件,在使用前需要引入这个插件。如果不想引入插件,可以自行实现代码生命周期功能。
PS:大家有更好的解决方案,欢迎在评论区交流。
参考资料
- uni-app 中利用 Promise 实现 onLaunch 异步回调后执行 onLoad
- 小程序app.onLaunch与page.onLoad异步问题的最佳实践
- 代理生命周期 | uni-simple-router
最新文章
- AXIS 调用 webservice服务时传递 服务器验证需要的用户名密码
- laravel 5.2 引入第三方类
- Mysql示例数据库employees.sql导入问题
- SQL Server output经典使用
- js获取location.href的参数实例代码
- HTML 页面加载动画效果
- 51Testing丛书新作《软件测试工程师面试秘籍》
- CSS开发经验
- 性能测试工具:AB
- 【高德地图API】那些年我们一起开发的APP—即LBS应用模式分享
- C#调用托管C++类(DLL)
- SQLserver2008r2安装过程
- Linux 终端 Bash 常用快捷键介绍及经验
- Java的多态及注意事项
- Ubuntu 18.04 启动root账号并授权远程登录
- aop(权限控制)
- js清除单选框所选的值
- Poj3984 迷宫问题 (BFS + 路径还原)
- web API简介(一):API,Ajax和Fetch
- Ubuntu14.04下codeblocks手动编译配置bost_1_57_0
热门文章
- CSS5:移动端页面(响应式)
- python爬虫---爬取王者荣耀全部皮肤图片
- 在 MarkDown 中添加表格(例如:在 CSDN 中添加表格)
- Spring Boot-@ImportResource注解
- oracle各种用户登录的方式
- Golang 源码解读 01、深入解析 strings.Builder、strings.Join
- 【Electron】Electron Icon 图标说明、及常见问题
- Docker部署Nginx启动成功,浏览器拒绝访问
- JAVA语言学习day16--7月22日
- 2021.11.09 P4824 [USACO15FEB]Censoring S与P3121 [USACO15FEB]Censoring G(KMP&;&;AC自动机)