评论

关于我在微信小程序学习初期,踩的最大坑,同步和异步(大佬教我写登录系列)

微笑小程序开发填坑笔记系列

最近在学小程序,今天在做登录校验。我写了个一键登录,然后通过云函数1获取openid,用过云函数2校验数据库看是否有这个openid的用户(用的.where().count()方法),有的话返回值res.result.total会是1,返回0就验证不通过。奔着这个逻辑出现了以下尴尬的情况:

const app = getApp()
var isLogin1=0;
Page({
    data: {
        userInfonull,
        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'获取用户信息',
            successasync (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 加上标识。

登录功能成功生效。


最后一次编辑于  2022-07-13  
点赞 3
收藏
评论

1 个评论

  • DEMON
    DEMON
    2022-10-27

    牛批,我跟你碰到的问题不能说差不多,只能说一模一样。

    2022-10-27
    赞同
    回复
登录 后发表内容