遇到的问题
最近在开发小程序,API实现了权限控制,需要先获取到token然后使用token请求接口,但是就遇到了一个问题,由于小程序wx.request()
方法是异步的,在app.js
执行request
后,各方法加载app.js
的全局数据时,无法按顺序加载,所以就出现了在token还未获取到就去请求其它API,导致API调用失败。
问题代码
const api = require('config/api.js');
App({
globalData: {
version: "1.5",
token: '',
uid: ''
},
onLaunch: function () {
this.login();
this.getAppInfo();
this.getTabList();
},
login: function () {
wx.login({
success: function (res) {
wx.request({
url: api.wxAppLogin,
header: {
'x-auth-wechat-app-code': res.code
},
success: function (res) {
if (res.data.code != 1) {
this.registerUser();
return;
}
this.globalData.token = res.data.data.token;
this.globalData.uid = res.data.data.id;
}
})
}
})
},
getAppInfo() {
wx.request({
url: api.option,
header: {
'x-auth-token': this.globalData.token
}
data: {
name: 'title'
},
success: function (res) {
if (res.data.code == 1) {
wx.setStorageSync('mallName', res.data[0].value);
}
}
})
},
getTabList(){
...
}
})
例如上面的代码,其实代码本没有错,但在这种场景下就必须得到解决。
login()
还未执行完毕,getAppInfo()
和getTabList()
可能就已经执行了,所以getAppInfo()
和getTabList()
拿token时肯定就拿不到,那么API肯定也就执行错误了。
解决问题
如果我们一段代码中,异步操作太多,又要保证这些异步操作是有顺序的执行,那我们的代码就看起来非常糟糕,就像这样的极端情况:
asyncFunc1(function(){
//...
asyncFunc2(function(){
//...
asyncFunc3(function(){
//...
asyncFunc4(function(){
//...
asyncFunc5(function(){
//...
});
});
});
});
});
多层回调嵌套,业务复杂了就有些不忍直视了,找了一下资料,看到大家推荐引入ES6的promise,如果我们改用Promise来处理,那么进行一层简单的包装即可。
function asyncFunc1(){
return new Promise(function (resolve, reject) {
//...
})
}
然后我看到了这个解决方案 :
https://github.com/cinoliu/-es6-promise
引入promiss后,然后看了一下他实现的util:wxRequest.js,但这里好像还并不能满足我的需求,这里实现的方法不能自定义header,所以自己改了一下,以get方法为例:
function getRequest(url, data, header) {
var getRequest = wxPromisify(wx.request)
return getRequest({
url: url,
method: 'GET',
data: data,
header: header
})
}
使用后代码大概是这样:
//index.js
const api = require('config/api.js');
var util = require('../../utils/util')
var wxApi = require('../../utils/wxApi')
var wxRequest = require('../../utils/wxRequest')
var app = getApp()
Page({
data: {
version: "1.5",
token: '',
uid: ''
},
onLoad: function () {
var that = this;
//1.获取code
var wxLogin = wxApi.wxLogin()
wxLogin().then(res => {
console.log('1.获取code成功了')
var url = api.wxAppLogin,;
var params = {},
var header = {
'x-auth-wechat-app-code': res.code
}
//2.获取token
return wxRequest.getRequest(url, params, header)
}).
then(res => {
console.log('2.获取token成功了')
this.globalData.token = res.data.data.token;
this.globalData.uid = res.data.data.id;
var url = api.option,
var params = {
name: 'title'
}
var header = {
'x-auth-token': res.data.data.token
}
return wxRequest.postRequest(url, params, header)
}).
then(res => {
console.log('3.获取app信息成功了')
console.log(res)
//4.获取系统信息
var wxGetSystemInfo = wxApi.wxGetSystemInfo()
return wxGetSystemInfo()
}).
then(res => {
console.log('4.成功了')
console.log(res)
//5.获取用户信息
var wxGetUserInfo = wxApi.wxGetUserInfo()
return wxGetUserInfo()
})
.finally(function (res) {
console.log('finally~')
wx.hideToast()
})
}
})
这样就能实现一步步走了,就不会存在文章开头说的情况了,但是我发现了一个问题,我觉得es-promise这个文件稍微有点大,就想着能不能有其他的办法,然后又看到了这个 :
https://github.com/skyvow/wx-extend
也是开源的小程序拓展插件,看了他实现的WxService - Promise API插件,看了一下,感觉更干净,也能解决我的问题,所以就用了一下。
import wxService from './plugins/WxService'
const api = require('config/api.js');
App({
globalData: {
version: "1.5",
token: '',
uid: '',
},
onLaunch: function () {
this.getStorageToken();
},
//获取token并赋值到全局变量token
getStorageToken() {
this.wxService = new wxService;
console.log(this.wxService)
//从缓存获取token
this.wxService.getStorage({
key: 'token'
}).then(
res => {
console.log("get token:", res);
this.globalData.token = res.data;
this.getSiteInfo();
this.getTabList();
},
).catch(
err => {
console.log("从缓存获取token失败")
this.login();
}
)
},
login: function(){
...
}
})
嗯至此我的问题也解决了,感谢开源作者,希望文章能帮到您。
参考资料
柒月君 2018-04-01 14:54
最近在研究小程序啊
我都原地踏步好久了