微信小程序全栈开发实践 第三章 微信小程序开发常用的API介绍及使用 -- 3.5 网络接口简介(五)基于Promise+await、async关键字改写登录模块

该博客介绍了如何将微信小程序的登录模块从回调函数方式改写为使用Promise和await/async,以提高代码可读性和易维护性。内容包括loginWithCallback函数的Promise改写,wx.checkSession和wx.login的处理,以及利用await简化错误处理。最后,展示了如何通过封装wx.request自动处理token和错误,以及对整个登录流程的优化。
摘要由CSDN通过智能技术生成

零、回顾

在上节课我们主要实践练习了Promise的三个方法,包括any、all、race。
现在我们对Promise变成已经有了一个大致的了解。
这节课我们尝试将登录模块使用Promise编程方式进行改写。

原来在lib/login.js这个模块中,函数loginWithCallback使用的是回调函数的方式通知消费者登录成功。
接下来我们在本课的源码里面将尝试使用Promise的方式进行改写。

一、loginWithCallback函数使用Promise改写

lib/login.js

function loginWithCallback2(e) {

  return new Promise((reslove, reject) => {
  	......
     `1.之前的代码逻辑复制粘贴过来`
  });



}

export default loginWithCallback2
function loginWithCallback2(e) {

  return new Promise((reslove, reject) => {
  	 `2.添加reslove,reject`
  	 ......
  	 const requestLoginApi = (code) => {
      //发起网络请求
      wx.request({
        ......
        success(res) {
          ......
        },
        fail(err) {
          ......
         reject(err);  
        }
      })
    }

  const onUserLogin = (token) => {
      ......
      // if (cb && typeof cb == 'function') cb(token);  注释cb代码
      reslove(token);
    }
     
  });


	// session_key 已经失效,需要重新执行登录流程
	wx.login({
	  ......
	  fail(err){
	    reject(err);
	  }
	})


}

export default loginWithCallback2
`完整版代码`

function loginWithCallback2(e) {

  return new Promise((reslove, reject) => {
    let {
      userInfo,
      encryptedData,
      iv
    } = e.detail
    console.log('userInfo', userInfo);

    const requestLoginApi = (code) => {
      //发起网络请求
      wx.request({
        url: 'http://localhost:3000/user/wexin-login2',
        method: 'POST',
        header: {
          'content-type': 'application/json'
        },
        data: {
          code: code,
          userInfo,
          encryptedData,
          iv
        },
        success(res) {
          console.log('请求成功', res.data)
          let token = res.data.data.authorizationToken
          wx.setStorageSync('token', token)
          onUserLogin(token)
          console.log('authorization', token)
        },
        fail(err) {
          console.log('请求异常', err)
          reject(err);
        }
      })
    }


    const onUserLogin = (token) => {
      getApp().globalData.token = token
      wx.showToast({
        title: '登陆成功了',
      })
      // startOneRequest(token);
      // if (cb && typeof cb == 'function') cb(token);
      reslove(token);
    }

    wx.checkSession({
      success() {
        //session_key 未过期,并且在本生命周期一直有效
        console.log('在登陆中');
        let token = wx.getStorageSync('token')
        if (token) onUserLogin(token)
      },
      fail() {
        // session_key 已经失效,需要重新执行登录流程
        wx.login({
          success(res0) {
            if (res0.code) {
              requestLoginApi(res0.code)
            } else {
              console.log('登录失败!' + res.errMsg)
              
            }
          },
          fail(err){
            reject(err);
          }
        })
      }
    })

  });

}

export default loginWithCallback2

index.js

// 3.2 登录之后,调用接口
startOneRequestWithLofinUtilMethod1(e) {
  ......

  `loginWithCallback(e, startOneRequest); 注释之前的代码`
  `改成promise的写法`
  loginWithCallback2(e).then(token=>{
    startOneRequest(token);
  });


},

`完整版代码`
// 3.2 登录之后,调用接口
startOneRequestWithLofinUtilMethod1(e) {
  const startOneRequest = (token)=>{
    wx.request({
      url: "http://localhost:3000/user/home",
      header:{
        'Authorization': `Bearer ${token}`
      },
      success(res) {
        if (res.errMsg === "request:ok") console.log("3.2--res1", res);
      },
      fail(err) {
        if (/^request:fail/i.test(err.errMsg)) console.log("3.2--err1", err);
      },
      complete(res) {
        console.log("3.2--complete1", res);
      }
    });
  }

  let token = wx.getStorageSync('token')
  if (token) {
    startOneRequest(token);
    return
  }

  // loginWithCallback(e, startOneRequest);
  loginWithCallback2(e).then(token=>{
    startOneRequest(token);
  });


},

在这里插入图片描述

二、await + async

在这里插入图片描述

我们可以对具体的每一个,比如像checkSession对它的调用再进行一个改造。
现在仅仅通过Promise,以及相关的all、race等方法,我们现在所能进行的改造是十分有限的。

因为像登录这个场景,它虽然调用了多个接口,但这些接口的调用它前后是有依赖关系的,
并不能简单的按照race或者any这样的逻辑进行改造。

在项目开发中,在很多情况下,我们使用Promise的场景都是比较杂乱的,都不是经典的,
这个时候,为了适应这种编程上的需要,在2016年,Javascript推出了ES7,
包括了两个与Promise编程相关的关键字,一个是await,一个是async

在这里插入图片描述

await操作符,它用于等待一个Promise对象,它只能在异步函数async function中使用,
在function前面必须使用async这样的一种关键字去修饰它。

在上面的代码中,func1它是一个返回Promise对象,它是一个异步操作。

f1是一个标识为async的函数,在它内部使用一个await关键字,去等待一个Promise对象。
await它会暂停当前的async funciton的执行,等待Promise函数处理完成。
如果Promise正常进入了接受状态,其回调的reslove函数,它的参数将作为await表达式的值返回,
然后继续执行下面的代码。

在这里插入图片描述

如果Promise它进入了拒绝状态,await表达式会把Promise函数的异常给抛出来,
当前的函数会中止执行,
在上面的代码中可以看出来,OK是不会打印出来的,
var z = await Promise.reject("error");这一行它会中止执行,
因为这句话它抛出了一个异常一个错误,然后这个代码在抛出异常以后,
它通过try catch 它就进入下面catch,它就打印error。

Promise.reject它代表的是创建一个有拒绝状态的Promise对象。

不是一个Promise对象
在这里插入图片描述

如果等待的它不是一个Promise对象,则返回这个值得本身。
20它不是一个Promise对象。

await关键字,它还可以用于同步操作,这可以保证我们代码风格的一致性

三、用await + async改写登录模块代码和调用代码

login.js

在这里插入图片描述

 wx.checkSession({
      success() {
        //session_key 未过期,并且在本生命周期一直有效
        console.log('在登陆中');
        let token = wx.getStorageSync('token')
        if (token) onUserLogin(token)
        `还差一块逻辑,就是token不存在,也要进行wx.login,
        所以checkSession 无论走到哪个,都要进行wx.login`
      },
      fail() {
        
        wx.login({
          success(res0) {
            if (res0.code) {
              requestLoginApi(res0.code)
            } else {
              console.log('登录失败!' + res.errMsg)
            }
          },
          fail(err) {
            reject(err);
          }
        })
      }
    })

function loginWithCallback3(e) {

  return new Promise(async (reslove, reject) => {
    let {
      userInfo,
      encryptedData,
      iv
    } = e.detail


    const app = getApp();
    try {
      app.wxp.checkSession();
    } catch (err) {
      reject(err);
    }

    let token = wx.getStorageSync('token')
    if (!token) {
      let res1 = await wx.login().catch(err => reject(err));
      let code = res1.code;
      let res = await app.wxp.request({
        url: 'http://localhost:3000/user/wexin-login2',
        method: 'POST',
        header: {
          'content-type': 'application/json'
        },
        data: {
          code: code,
          userInfo,
          encryptedData,
          iv
        }
      }).catch(err => reject(err));

      token = res.data.data.authorizationToken;
      wx.setStorageSync('token', token);
      onUserLogin(token);

      const onUserLogin = (token) => {
        getApp().globalData.token = token
        wx.showToast({
          title: '登陆成功了',
        })
        reslove(token);
      }

    }


  });



}

export default loginWithCallback3

index.js

 // 3.2 登录之后,调用接口
  startOneRequestWithLofinUtilMethod1(e) {
    ......

    // loginWithCallback(e, startOneRequest);
    loginWithCallback3(e).then(token=>{
      startOneRequest(token);
    });


  },
`完整版代码`
startOneRequestWithLofinUtilMethod1(e) {
 const startOneRequest = (token)=>{
   wx.request({
     url: "http://localhost:3000/user/home",
     header:{
       'Authorization': `Bearer ${token}`
     },
     success(res) {
       if (res.errMsg === "request:ok") console.log("3.2--res1", res);
     },
     fail(err) {
       if (/^request:fail/i.test(err.errMsg)) console.log("3.2--err1", err);
     },
     complete(res) {
       console.log("3.2--complete1", res);
     }
   });
 }

 let token = wx.getStorageSync('token')
 if (token) {
   startOneRequest(token);
   return
 }

 // loginWithCallback(e, startOneRequest);
 loginWithCallback3(e).then(token=>{
   startOneRequest(token);
 });


},

运行
在这里插入图片描述

四、catch的简化

目前,我们的wx.request方法还有一个问题,
就是在网络请求发生错的时候,它每个请求都需要你去catch一下,
其实这个代码还可以进一步的简化。
因为只有成功,进入接受状态的时候,然后才可以进入下一步代码的执行,
如果说不能成功进入的话,上面的话,无论我们catch或者不catch的话,其实它这个结果都是一样的。

接下来我们在本课的源码中,对wxp对象进行进一步的一个改造,
改造以后,相关的catch代码就不需要了。

同时将token自动放在网络请求的header中,
如果这个token存在的话,毕竟在每个请求中,手动放入这个token并不是一个好办法。
那么我们一起来看一看,具体的代码怎么去写。

app.js
在这里插入图片描述

//app.js

// 初始化只需要初始化一次,只需要在app.js初始化一次就可以了,这样每个页面都可以应用wxp对象
import { promisifyAll } from 'miniprogram-api-promise';
const wxp = {}
promisifyAll(wx, wxp)

wxp.request2 = function (args) {
  let token = wx.getStorageSync('token');
  if (token) {
    if (!args.header) args.header = {}
    args.header["Authorization"] = `Bearer ${token}`
  }
  return wxp.request(args).catch(err => console.log("err", err))
}


App({
  wxp: wxp,
  ......
})

在这里插入图片描述
login.js


function loginWithCallback3(e) {

  return new Promise(async (reslove, reject) => {
    let {
      userInfo,
      encryptedData,
      iv
    } = e.detail


    const app = getApp();
    try {
      app.wxp.checkSession();
    } catch (err) {
      reject(err);
    }

    let token = wx.getStorageSync('token')
    if (!token) {
      let res1 = await wx.login().catch(err => reject(err));
      let code = res1.code;
      let res = await app.wxp.request2({
        url: 'http://localhost:3000/user/wexin-login2',
        method: 'POST',
        header: {
          'content-type': 'application/json'
        },
        data: {
          code: code,
          userInfo,
          encryptedData,
          iv
        }
      });

      token = res.data.data.authorizationToken;
      wx.setStorageSync('token', token);
      onUserLogin(token);

      const onUserLogin = (token) => {
        getApp().globalData.token = token
        wx.showToast({
          title: '登陆成功了',
        })
        reslove(token);
      }

    }


  });



}

export default loginWithCallback3

index.js

// 3.2 登录之后,调用接口
async  startOneRequestWithLofinUtilMethod1(e) {
  // const startOneRequest = (token)=>{
  //   wx.request({
  //     url: "http://localhost:3000/user/home",
  //     header:{
  //       'Authorization': `Bearer ${token}`
  //     },
  //     success(res) {
  //       if (res.errMsg === "request:ok") console.log("3.2--res1", res);
  //     },
  //     fail(err) {
  //       if (/^request:fail/i.test(err.errMsg)) console.log("3.2--err1", err);
  //     },
  //     complete(res) {
  //       console.log("3.2--complete1", res);
  //     }
  //   });
  // }

  // let token = wx.getStorageSync('token')
  // if (!token) {
  //   // startOneRequest(token);
  //   startOneRequest();
  //   return
  // }

  // loginWithCallback(e, startOneRequest);
  // loginWithCallback3(e).then(token => {
  //   // startOneRequest(token);
  //   startOneRequest();
  // });


  if (!wx.getStorageSync('token')) {
    await  loginWithCallback3(e);
  }

  let res1 = await getApp().wxp.request2({
    url: "http://localhost:3000/user/home",
  });
  console.log("res1",res)



},

运行
在这里插入图片描述

五、总结

但是目前还有一个问题,我们目前的网络请求,都必须通过一个open-type,等于getUserInfo的button发起,
否则我们的接口请求可能就会失败,我们不能再javascript代码中发起一个网络请求吗?

如果我们在javascript代码中发起网络请求的时候,如果发现用户未登录,
能否先引导用户去登录,然后再继续接口的调用。答案肯定是可以的。
事实上很多小程序也是这么实现的。默认情况下,一些小程序的浏览时不需要登录的,
只有进行写入操作的时候才要求用户进行登录。这个问题就留给自己思考一下。
这节课我们主要基于Promise加awaitasync关键字改写了登录模块的代码,
但是我们在自动登录这一块,还仍有问题,
下节课我们看一下,如何在接口调用中实现自动登录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值