《微信小程序开发之异步转同步》

问题概述

基于小程序request请求是异步的特性,app.js onLaunch()中的请求与index.js onLoad()中的请求是同时进行的,导致onLoad()中如果有基于onLaunch()返回的数据的请求,会有报错,导致onLoad()中request请求的数据“第一次”无法正常获取。

我的小程序中所有的requset请求都需要在header中带着用户唯一的token进行发起,而token是在app.js onLaunch()中的wx.login()返回中获取到的(由code到后台换取),之后通过wx.setStorageSync('token', res.data)存到小程序中。要解决问题,就需要解决request请求异步的问题,而且是在两个js文件之间。

使用Promise()

稍微说一下promise

1
2
3
4
5
6
7
8
9
10
11
12
13
var promise = new Promise(function(resolve, reject) {
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});

promise.then(function(value) {
// success
}, function(value) {
// failure
});

Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 方法和 reject 方法。

  • 如果异步操作成功,则用 resolve 方法将 Promise 对象的状态,从「未完成」变为「成功」(即从 pending 变为 resolved);
  • 如果异步操作失败,则用 reject 方法将 Promise 对象的状态,从「未完成」变为「失败」(即从 pending 变为 rejected)。

接下来在小程序中引入promise库。到bluebird官网中下载压缩版本的promise库。直接打开bluebird.core.min.js,复制代码。

Bluebird is a fully featured JavaScript promises library with unmatched performance.

小程序内新建一个promise.js文件,将bluebird.core.min.js中的代码复制进去。
app.js中通过require引入:
1
2
<!-- app.js -->
const Promise = require('units/promise.js');

这样就可以在小程序内使用promise了,该库大小大概在64kb左右,可以接受。
接下来直接贴代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!-- app.js -->
App({
onLaunch: function(){
<!-- 调整代码结构,原本在此进行的wx.login操作放到下面去 -->
...
},
//登录,获取token
getToken: function(){
let _this = this;
return new Promise(function(resolve, reject){
wx.checkSession({
success: function (res) { resolve(res); },
fail: function (res) {
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
if (res.code) {
wx.request({
url: CONFIG.loginUrl,
data: {
code: res.code
},
header: {
'shopId': CONFIG.shopId
},
method: 'POST',
success: res => {
wx.setStorageSync('token', res.data); //储存返回的token
resolve(res);
}
})
} else {
console.log('获取用户登录态失败!' + res.errMsg);
reject('error');
}
}
})
}
})
})
}
})

接下来在index.js中处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const app = getApp();
Page({
onLoad: function(){
let token = wx.getStorageSync('token');
if (token == ''){
//第一次登录,获取登录状态
app.getToken().then(function (res) {
_this.getData(); //此时token必然已经获取到,且getData()在此时才会执行
})
}else{
//有token的情况直接获取数据
_this.getData();
}
},
//获取数据
getData: function(){
wx.request({
header: {
'token': wx.getStorageSync('token')
},
url: 'https://xxxxx.xxxxx',
method: 'GET',
success: res => {
console.log(res);
}
})
}
})

这时候清除一下开发工具的缓存,再次编译页面,打开调试面板的network,可以看到index.js中的wx.request请求是在wx.login()的success后才开始的,这样就达到了我们的目的,问题解决。