微信小程序开发小技巧:微信请求 Promise 化
2.1 使用现成的库
安装 Promise 库 wx-promise-pro,记得一定要带 -s
或 --production
,要不然无法构建成功。
npm i -S wx-promise-pro
然后在 app.js
中:
import { promisifyAll } from 'wx-promise-pro'
promisifyAll() // promisify all wx api
App({ ... })
之后就可以正常使用了:
wx.pro.showLoading({
title: '加载中',
mask: true
})
.then(() => console.log('in promise ~'))
2.2 自己实现
其实我们可以自己来实现一个这样的库,原理很简单,以原生 API 的 wx.request 为例:
// 原生 API 使用方式
wx.request({
url: '', // 请求的 url
data: {}, // 参数
method: '', // post、get
success: res => {
// 请求成功回调函数,res为回调参数
},
fail: res => {
// 请求失败回调函数,res为回调参数
}
})
如果我们将其 Promise 化,应该的调用方式希望是:
// Promise 化后的期望使用方式
wx.pro.request({
url: '', // 请求的 url
data: {}, // 参数
method: '' // post、get
})
.then(res => {
// 请求成功回调函数,res为回调参数
})
.catch(res => {
// 请求失败回调函数,res为回调参数
})
并且 then
函数返回的是一个 Promise 对象,让这个函数可以不断链式调用下去,所以首先需要 new
出来一个 Promise 对象:
function request(opt) {
return new Promise((resolve, reject) => {
wx.request({
...opt,
success: res => { resolve(res)},
fail: res => {reject(res)}
})
})
}
这里代码我们可以进一步改进,由于 success
、fail
这里传入的参数只是由 resolve
、reject
方法执行了下,所以可以直接传入 resolve
、reject
方法即可。
另外,由于其他小程序原生 API 格式一致,所以我们可以使用柯里化方法,来将其他需要进行 Promise 化的 API 进行处理:
function promisify(api) {
return (opt = {}) => {
return new Promise((resolve, reject) => {
api({
...opt,
fail: reject,
success: resolve
})
})
}
}
然后,将柯里化方法执行的结果作为新的 Promise 化的 API 挂载到 wx.pro
对象上:
// 将指定 API 进行 Promise 化
wx.pro.request = promisify(wx.request)
// 使用
wx.pro.request({...})
.then(...)
然后为了方便我们使用其他方法,可以循环将 wx
对象上可以被 Promise 化的方法比如 request
、scanCode
、showToast
、getUserInfo
等一一挂载到 wx.pro
对象上,使用时可以直接 wx.pro.xx
,由于这个方法执行返回的是一个 Promise 对象,因此可以像其它 Promise 化的对象那样使用。
事实上,不知不觉,我们就自己实现了 wx-promise-pro
的源码,这个库的核心代码也就是上面那这几行 ?
2.3 在项目中使用
有了上面的工具后,我们可以将其使用在项目中,为了不在项目中遍布 wx.request
或 wx.pro.request
这里可以简单进行封装,新建两个文件如下:
// utils/api/fetch.js 封装请求方法、请求拦截器
const app = getApp()
const BaseUrl = 'http://172.0.0.1:7300/mock'
const TokenWhiteList = [
'/app/user/get-by-code' // 不需要鉴权的api手动添加到这里
]
/**
* 设置请求拦截器
* @param params 请求参数
*/
const fetch = (params = {}) => {
// 拦截器逻辑
if (!TokenWhiteList.includes(params.url)) {
params.header = {
'content-type': 'application/json', // 默认值
'token': app.globalData.token || ''
}
}
if (params.url.startsWith('/')) { // 拼接完整URL
params.url = BaseUrl + params.url
}
// 返回promise
return wx.pro.request({ ...params })
.then(({ data: { code, message, data } }) => {
// ... 各种异常情况的逻辑处理
// 与后端约定 code 20000 时正常返回
if (code === 20000) return Promise.resolve(data)
return Promise.reject(message)
})
}
export { fetch }
然后再将所有 API 封装到单独的文件中集中管理:
// utils/api/apis.js 封装所有请求 API
import { fetch } from './fetch'
/* 根据微信code获取用户信息 */
const appUserGetByCode = ({ code } = {}) => fetch({
url: '/app/user/get-by-code',
data: { code }
})
/* 扫码登录 */
const appUserQrLogin = ({ qrCode } = {}) => fetch({
method: 'POST',
url: '/app/user/qr-login',
data: { qrCode }
})
/* 个人信息 */
const appUserInfo = () => fetch({
url: '/app/user/info'
})
/* 系统参数获取,数据字典 */
const appSysParamListByParam = () => fetch({
url: '/app/sys-param/list-by-param'
})
/* 数据字典所有 */
const appSysParamListAll = () => fetch({
url: '/app/sys-param/list-all'
})
export {
appSysParamListAll, // 数据字典所有
appSysParamListByParam, // 系统参数获取,数据字典
appUserGetByCode, // 根据微信code获取用户信息
appUserQrLogin, // 扫码登录
appUserInfo // 个人信息
}
在要使用 API 的地方就可以这样引入:
import * as Api from '../../utils/api/apis.js' // 相对路径
// 使用方式
Api.appSysParamListAll()
.then(({ dataList }) => this.upData({ sysParamList: dataList }))
.then(() => {
const keyList = this.data.sysParamList.map(T => T.key)
this.upData({
keyList,
formData: { keys: keyList }
})
})
使用方式就很舒服,这里使用到了 upData,就是下面我要介绍的内容,是在下非常推介的小程序工具~