关于微信小程序中异步登录的问题? 文件执行顺序的问题 与promise问题

晨光普照
  • 277

目前我将登录操作写在了 app.js 中, 获取到微信的 code 后,向自己的服务器获取验证 access-token .
代码如下

app.js

    onLaunch: function () {
        wx.login({
            success: res => {
                // 发送 res.code 到后台换取 openId, sessionKey, unionId
                config.code = res.code;
                this.initUserInfo();
            }
        })
    },
    
    
    // 初始化用户信息
    initUserInfo: function () {
        wx.request({
            url: config.baseUrl + "/index.php?m=Api&c=User&a=initUserInfo",
            method: 'POST',
            header: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            data: {
                source_type: 'wxapp',
                code: config.code,
            },
            success: function (res) {
                if (res.data.status == true) {
                    
                    config.uid = res.data.data.uid;
                    config.accessToken = res.data.data.wxapp_access_token;
          
                } else if (res.data.status == false) {
                    console.log(res.data.data);
                } else {

                }
            }
        })
    },

在另一个文件 met.js 中需要通过获取的 uid accessToken 来请求获取数据.
代码如下
met.js

    eggGetRemoteWords: function() {

        var self = this;
        wx.request({
            url: app.config.baseUrl + "/index.php?m=Api&c=Learning&a=getLearningWord",
            method: 'POST',
            header: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            data: {
                uid: app.config.uid,
                access_token: app.config.accessToken
            },
            success: function (res) {
                if (res.data.status == true) {
                    self.setData({
                        'word.wordArray': res.data.data,
                    }) 
                    var total = self.data.word.wordArray.length;
                    self.setData({ "word.wordInfo.total": total });

                } else if (res.data.status == false) {

                } else {

                }
            }
        })
    },

但是目前总是 met.js 中的函数 eggGetRemoteWords 总早于 app.j s中 initUserInfo 登录函数执行,导致无法获取到数据 因为 js 异步的原因. 请问大家这应该怎么处理呢? 我了解到 promise 请问如果目前的需求将如何实现呢?

回复
阅读 2.3k
4 个回答

eggGetRemoteWords 需要在 initUserInfo 中,登录成功的 success 回调中执行,所以可以这样定义

function initUserInfo(callback) {
    wx.request({
        ...
        success: function() {
            ....
            config.uid = res.data.data.uid;
            config.accessToken = res.data.data.wxapp_access_token;
            callback(config);
            ....
        }
    });
}

然后,这样调用

initUserInfo(() => eggGetRemoteWords());

但是一般来说,用户信息取到之后只要不过期,是不应该反复去取的,所以取用户信息的部分可以封装一下

function requestUserInfo(callback) {
    if (config.uid && config.accessToken) {
        callback(config);
    } else {
        initUserInfo(callback);
    }
}

之后调用也相应的改成

requestUserInfo(() => eggGetRemoteWords());

上面都是采用的回调的方式来处理异步,如果想用 Promise(说实在的,我不清楚小程序目前对 Promise 支持得如何)

function initUserInfo() {
    return new Promise((resolve, reject) => {
        wx.request({
            ....
            success: function(res) {
                if (....) {
                    config.uid = ...;
                    config.accessToken = ...;
                    resolve(config);
                } else {
                    reject(res);
                }
            },
            fail: function(...args) {
                reject(res);
            }
        });
    });
}

function requestUserInfo() {
    return new Promise((resolve, reject) => {
        if (config.uid && config.accessToken) {
            resolve(config);
        } else {
            initUserInfo().then(resolve).catch(reject);
        }
    });
}

// 调用
requestUserInfo().then(eggGetRemoteWords);
// 或者
// requestUserInfo().then(eggGetRemoteWords());

你的意思莫非是 封装一下 request

function request(url, data, method){
    return new Promise(function(resolve,reject){
        resolve(data);
 })
}

  function initUserInfo(){
     return request('123', {a: 1}, 'post');
  }
  function eggGetRemoteWords () {
     return request('23423', {b: 2}, 'post');
  }
  
  initUserInfo().then(data => {
      console.log(data.a)
      return eggGetRemoteWords()
  }).then(data => console.log(data.b))

代码如下,可能 有错需要你自己修改

function request(url, data, method){
      return new Promise(function(resolve,reject){
         //网络请求
         wx.request({
           url: url,
           data: data,
           method: method, // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
           header: {
               // 默认
               'content-type': 'application/json' 
           }, // 设置请求的 header
           success: function(res){
             // success网络请求成功
             if(res.statusCode !== 200){
                 reject({error:'服务器忙,请稍后重试',code:500});
                 return;
             }
             resolve(res.data.data);
           },
           fail: function(res) {
             // fail调用接口失败
             reject({error: res.error ,code:0});
           },
           complete: function(res) {
             // complete
           }
         })
      })
   }

    initUserInfo:function(...){
       return request(url,{...}, 'post');
    }
    eggGetRemoteWords:function (...) {
       return request(url,{...}, 'post');
    }
    
    initUserInfo().then(() => eggGetRemoteWords())
    .catch(reason => void console.log(resaon))

用async函数调用,initUserInfo和eggGetRemoteWords都封装成promise

用promise二次封装下你的request就行了

宣传栏