最近在学小程序,今天在做登录校验。我写了个一键登录,然后通过云函数1获取openid,用过云函数2校验数据库看是否有这个openid的用户(用的.where().count()方法),有的话返回值res.result.total会是1,返回0就验证不通过。奔着这个逻辑出现了以下尴尬的情况:
const app = getApp()
var isLogin1=0;
Page({
data: {
userInfo: null,
isLogin:0
},
onLoad(options) {
},
chkuid() {
let id = app.globalData.user_openid
//登录核对用户ID
wx.cloud.callFunction({
name: 'getWxIdChkFun',
data: {
id: id
}
})
.then(res => {
console.log("校对完毕!", res)
console.log("chkuid里的",res.result.total)
isLogin1= res.result.total
console.log("chkuid里的",isLogin1)
this.setData({
isLogin: res.result.total
})
console.log("chkuid里的",this.data.isLogin)
})
.catch(res => {
console.log("校对失败!", res)
})
},
login() {
let isUser = 0
this.chkuid()
isUser = isLogin1
console.log('login里的isUser1',isUser)
isUser=this.data.isLogin
console.log('login里的isUser2',isUser)
},
})
问题非常尴尬,login执行完了chk的结果才出来。经过“茜茜又困了🐽”大佬解惑,我发现login里的代码块其实是同步执行的,也就是按顺序一条一条下来,但是执行到第二条chkuid进入函数内部是,发现这里面的东西是异步的,于是系统开了个支线继续跑chkuid这个函数,因为那货是异步所以login接着往下执行,但是chkuid的运算耗时比那两个Log长,所以出现了先把两个log输出,再输出chkuid结果的现象。蛋疼的地方在于我得用到chkuid里的total,所以这种操作让我没法做isLogin==1的判断。
我百度了下,发现解决这种情况的方法,好像是用Promise或async/await,于是舔着脸又去抱大腿,这回大佬上了硬菜,码图并茂的给我科普了下两种方式的写法:
一、Promise写法:
chkuid() {
let id = app.globalData.user_openid
return new Promise((resolve,reject)=>{
wx.cloud.callFunction({
name:"getWxIdChkFun",
data:{
id:id
}
})
.then(res=>{
console.log("校验成功",res)
resolve(res.result.total)
})
.catch(err=>{
console.log("校验失败",err)
reject(err)
})
})
},
login() {
let isUser=0
this.chkuid().then(res=>{
isUser=res
console.log("then里的isUser",isUser)
})
console.log("then外的isUser",isUser)
写到这里,又比较尴尬,为啥这个isUser在then之外还是0,我想得到的是一个在login里随便都能用的变量。。。。(原因找到了,详见下文)
大佬教的方法二:async和await
chkuid() {
let id = app.globalData.user_openid
return new Promise(resolve => {
wx.cloud.callFunction({
name: "getWxIdChkFun",
data: {
id: id
}
})
.then(res => {
isLogin1 = res.result.total
this.setData({
isLogin: res.result.total
})
resolve()
})
.catch(err => {
console.log("校验失败", err)
reject(err)
})
})
},
async login() {
let isUser = 0
await this.chkuid()
isUser = isLogin1
console.log('login里的isUser1', isUser)
isUser = this.data.isLogin
console.log('login里的isUser2', isUser)
}
此时得到了我理想的效果,在chkuid中把res的结果抛给一个全局变量(通过Page外部的var temp或是this.setData()给到Page.data里都行),然后在其他函数中就能随意使用这个变量。
————————————————————————————————————————————————————————————————————
经过详细查阅大佬给的两串代码,发现其实chkuid的写法是一样的,无非一个是在里面给全局变量赋值,然后resolve()返回空,另一个是不给全局变量赋值,resolve(res)返回res的Promise。
但是底下调用时,对应的有两种方法
(一)如果chkuid里的then赋值给全局变量了,login里直接用就完事了。
(二)如果chkuid里的then没赋值给全局变量,而是resolve(res)了,那么login中要获得这个值就得用这种写法
let isUser=0
this.chkuid().then(res=>{
isUser=res
})
现在就剩一个问题了,为啥这个isUser明明成了1,出了那个then又变0了?
————————————————————————————————————————————————————————————————————
2022/7/13更新:
上述问题经过“茜茜又困了🐽”大佬帮我解惑,原来不是没赋值成功,还是异步的问题,在外面那个log加个SetTimeOut稍微延迟下主进程(让进程飞一会儿~),就也能输出1了。
我本以为事情到此结束,结果,更大的坑来了。我这个登录页面的本意是:
通过app.js里调用云函数获取openid,然后在login.js里写了两个函数,一个是login,一个是chkuid。chkuid调用另一个云函数,那个云函数的作用是把openid的值跟云数据库User表匹配,用的.count方法,如果这个openid在User表里有,那返回的res.result.total会为1,为0则表示没有这个用户。
问题来了,不管我怎么按,右边模拟器都不会弹框提示我得授权,err输出fail can only be invoked by user TAP gesture。问题是你授权界面弹都没弹出来啊。这个问题崩溃了一天。
后来CSDN上找到另一个大佬的帖子,https://blog.csdn.net/qq_45233592/article/details/121910930,大概意思是getUserProfile跟async/await八字不合。
人在迷茫的时候就是死马当活马医,也不管是不是一样了(没仔细看uni.,不是wx. )
跟“茜茜又困了🐽”大佬交流了一番,大佬斩钉截铁的说肯定还是异步问题,跟我上面那玩意儿没关系。让我尝试Promise写法试试。于是有了以下代码
chkuid() {
let id = app.globalData.user_openid
return new Promise(resolve => {
wx.cloud.callFunction({
name: "getWxIdChkFun",
data: {
id: id
}
})
.then(res => {
this.setData({
isLogin: res.result.total
})
//resolve()
resolve(res.result.total)
})
.catch(err => {
console.log("校验失败", err)
reject(err)
})
})
},
login() {
let isUser=0
this.chkuid().then(res=>{
isUser=res
console.log(isUser)
wx.getUserProfile({
desc: '获取用户信息',
success: (res) => {
console.log(res.userInfo)
if (isUser == 1) {
//设置全局用户信息
app.globalData.userInfo = res.userInfo
//设置局部用户信息
this.setData({
userInfo: res.userInfo
})
wx.switchTab({
url: '/pages/today/today'
})
} else {
wx.showToast({
icon: 'error',
title: '未授权用户',
})
}
},
fail: (err => {
console.log(err)
})
})
})
},
依然得到那个结果。。。。。
直到刚才,大佬私信我,为啥不试试,把chkuid放在success里呢,于是我修改代码
login() {
wx.getUserProfile({
desc: '获取用户信息',
success: async (res) => {
let isUser = 0
await this.chkuid()
isUser = this.data.isLogin
console.log(isUser)
//确认能拿到total值后,开始弹窗
console.log(res.userInfo)
if (isUser == 1) {
//设置全局用户信息
app.globalData.userInfo = res.userInfo
//设置局部用户信息
this.setData({
userInfo: res.userInfo
})
wx.switchTab({
url: '/pages/today/today'
})
} else {
wx.showToast({
icon: 'error',
title: '未授权用户',
})
}
},
fail: (err => {
console.log(err)
})
})
},
把chkuid写在Success里,然后在找之前CSDN上的那个人的写法,在success: async (res)=>{} 和 await this.chkuid 加上标识。
登录功能成功生效。
牛批,我跟你碰到的问题不能说差不多,只能说一模一样。