【钉钉小程序】解决app.js onLaunch异步请求,在请求未执行完就进入page onLoad 的问题

文章描述了在开发小程序时遇到的挑战,即如何在首页加载前正确获取并使用token。通过分析小程序的执行顺序和生命周期,作者尝试了在app.js中定义回调函数来处理token,但未能成功。最终解决方案是将首页的数据获取逻辑放在一个单独的方法中,在onLoad中调用,确保在所有准备工作完成后执行。这种方法解决了异步问题,使得首页能正确显示数据。
摘要由CSDN通过智能技术生成

问题场景

最近在写小程序项目的过程中,真的是每走一步都是个“巨坑”。这次在实现免登录的过程中,我们需要在app.js里先拿到返回的token之后,在首页携带token发送请求获得首页需要展示的数据。

OK,这是我们想要小程序执行的顺序,但是小程序的执行顺序是先执行app.js onLaunch,通过dd.getAuthCode获取免登授权码,然后通过 access-tokencode 获取 userid ,根据 userid 获取 token 。这整个过程都是异步的,那么我们在page onload里面需要携带token请求数据时,onLaunch里的异步请求还没有拿到token,但是此时page onload在还未拿到数据的情况下就已经展示出来了。

给大家看一下控制台的输出顺序:

在这里插入图片描述
可以看出来先执行了home页的数据输出,之后app里请求到了数据也跟home页无关了,因为home页已经执行完了。

解决过程

有的文章上说在app.js上自定义一个函数(下行代码中的tokenCallBack方法),当home.js没有拿到token的时候,就调用app里的这个方法获取token之后再执行下面的代码。

home.js代码:

const app = getApp();
Page({
  data:{
    // 存储首页所有的展示信息
    allList:[],
  },
  async onLoad() {
    // 从本地获取 token 
    let token = dd.getStorageSync({ key: 'token' }).data;
    // 判断本地是否有 token,如果没有,就在本地存一个 token,如果有 token,就直接调用接口
    if (token == null) {
      // 在顶级对象里面添加一个 tokenCallBack 方法
      app.tokenCallBack = async (token) => {
        if (token) {
          dd.setStorageSync({
            key: 'token',
            data: token
          })
          // 发起请求,请求接口
          let result = await app.httpsReq('GET', '/**/**')
          if(result.status === 200){
            this.setData({
              allList : result.data.data
            })
          }
        }
      }
    } else {
      // 如果有 token ,就直接发起请求
      let result = await app.httpsReq('GET', ''/**/**'')
    }
  },
});

app.js代码:

APP({
  onLaunch(options) {
    // 调用 istoken方法,实现免登陆
    this.isToken();
  },
  isToken(){
    // 将顶级对象的 this 存储到 this2 中
    const this2 = this
    // 获取免登授权码(方法 API 文档提供)
    dd.getAuthCode({
      success:function(res){
        // 存储 authorCode 
        this.authCode = res.authCode
        // 将方法 getAuthCode 的 this 存储到 _this 中
        let _this = this
        // 根据 appkey 和 appsecret 获取 access-token
        dd.httpRequest({
          url:'https://oapi.dingtalk.com/gettoken?appkey=**&appsecret=**',
          method:'GET',
          success: (res) => {
            _this.access_token = res.data.access_token
            // 根据 access-token 和 code 获取 userid 
            dd.httpRequest({
              url:'https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token=' + _this.access_token + '&code=' + _this.authCode,
              method:'POST',
              success: async(res) =>{
                _this.userid = res.data.result.userid
                // 根据 userid 获取 token
                let result = await this2.httpsReq('POST','/**/**',{'userid':_this.userid})
                // tokenCallBack 方法用于在本地存储 token
                if(this2.tokenCallBack){
                  this2.tokenCallBack(result.data.data.token)
                }
              }
            })
          }
        })
      },
      fail:function(err){
        console.log(err);
      }
    })
  },
})

很遗憾,还是没能解决这个问题。期间也测试了很多种写法,但是如果不解决这个异步的问题,结果都是一样的。

最终代码

最后我搭档无意间点进了一篇文章,上面的写法都是一样的,只不过是把home.js 里写在onLoad中的代码提到了一个方法里(下行中的getdata()),然后在onLoad里调用这个方法,就解决这个问题了。。。说实话,很草率,但确实有用…

home.js代码:

const app = getApp();
Page({
  data: {
    // 存储首页所有的展示信息
    allList: [],
  },
  onLoad() {
    // 获取首页数据
    this.getdata()
  },
  // 用来发起请求获取首页数据的方法
  async getdata() {
    // 从本地获取 token 
    let token = dd.getStorageSync({ key: 'token' }).data;
    // 判断本地是否有 token,如果没有,就在本地存一个 token,如果有 token,就直接调用接口
    if (token == null) {
      // 在顶级对象里面添加一个 tokenCallBack 方法
      app.tokenCallBack = async (token) => {
        if (token) {
          // 将 token 存到本地
          dd.setStorageSync({
            key: 'token',
            data: token
          })
          // 发起请求,请求接口
          let result = await app.httpsReq('GET', '/**/**')
          if (result.status === 200) {
            // 通过 setData 修改数据
            this.setData({
              allList: result.data.data
            })
          }
        }
      }
    }
    else {
      // 如果有 token ,就直接发起请求
      let result = await app.httpsReq('GET', '/**/**')
      if (result.status === 200) {
        // 通过 setData 修改数据
        this.setData({
          allList: result.data.data
        })
      }
    }
  },
});

app.js代码:

APP({
  onLaunch(options) {
    // 调用 istoken方法,实现免登陆
    this.isToken();
  },
  isToken(){
    // 将顶级对象的 this 存储到 this2 中
    const this2 = this
    // 获取免登授权码(方法 API 文档提供)
    dd.getAuthCode({
      success:function(res){
        // 存储 authorCode 
        this.authCode = res.authCode
        // 将方法 getAuthCode 的 this 存储到 _this 中
        let _this = this
        // 根据 appkey 和 appsecret 获取 access-token
        dd.httpRequest({
          url:'https://oapi.dingtalk.com/gettoken?appkey=**&appsecret=**',
          method:'GET',
          success: (res) => {
            _this.access_token = res.data.access_token
            // 根据 access-token 和 code 获取 userid 
            dd.httpRequest({
              url:'https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token=' + _this.access_token + '&code=' + _this.authCode,
              method:'POST',
              success: async(res) =>{
                _this.userid = res.data.result.userid
                // 根据 userid 获取 token
                let result = await this2.httpsReq('POST','/**/**',{'userid':_this.userid})
                // tokenCallBack 方法用于在本地存储 token
                if(this2.tokenCallBack){
                  this2.tokenCallBack(result.data.data.token)
                }
              }
            })
          }
        })
      },
      fail:function(err){
        console.log(err);
      }
    })
  },
})

我跟我搭子想了很多种猜测,来解释为什么把这些代码提到一个方法里,就可以解决这个问题,但是都觉得没有确切的知识支持。

我觉得比较合理的解释可能就是,小程序首次启动或页面首次加载时,会先执行初始化,初始化data中的数据和自定义的一些方法完成之后,会触发 onLaunchonLoad 回调函数,此时数据和方法都已经渲染好了,直接拿来用就ok了。但是官方文档并没有很详细地说明小程序页面的生命周期过程中分别都做了哪些准备工作,所以上面我们的猜测可能是错误的,但是我们实在想不到更好的解释了。

如果大家有其他或更好的解决方法,欢迎不吝赐教!
如有误,请指正!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值