见到wx.request
的第一眼,就让我想起了$.ajax
这东西,使用起来确实有很多不方便,不能忍,幸好小程序是支持ES6语法的,所以可以使用promise稍加改造。
先来说说wx.request为什么不能忍。
铺垫:“看得见却抓不住“的异步请求
-
Page({
-
data: {
-
myData:
''
-
},
-
// loadMyData函数用于打印myData的值
-
loadMyData () {
-
console.log(
'获取到的数据为:' +
this.data.myData)
-
},
-
// 生命周期函数onload用于监听页面加载
-
onload:
function () {
-
wx.request({
-
url:
'https://api',
// 某个api接口地址
-
success:
res => {
-
console.log(res.data)
-
this.setData({
-
myData: res.data
-
})
-
console.log(
this.data.myData)
-
}
-
})
-
// 调用之前的函数
-
this.loadMyData()
-
}
-
})
-
复制代码
然后我们会在控制台到这样的结果:
这其实是一个很简单的异步问题,wx.request是异步请求,JS不会等待wx.request执行完毕再往下执行,所以JS按顺序会先执行this.loadMyData(),等服务器返回数据以后,loadMyData()早就执行完了,当然也就没有拿到值啦。
其实我们在同步流程中才说“返回”,异步没有“返回”这个概念(或者说异步返回是没有意义的),异步对应的是“回调”,也就是说,对于一个异步函数,我们应该传入一个“回调函数”来接收结果。
初步解决:通过回调接收结果
最简单的解决方案,就是把需要使用异步数据的函数写在回调里:
-
...
-
onload:
function () {
-
wx.request({
-
url:
'https://api',
// 某个api接口地址
-
success:
res => {
-
console.log(res.data)
-
this.setData({
-
myData: res.data
-
})
-
console.log(
this.data.myData)
-
// 把使用数据的函数写在回调函数success中
-
this.loadMyData()
-
}
-
})
-
}
-
复制代码
这样就可以正确输出了:
但是如果逻辑复杂,需要多层异步操作,会出现怎么样的情况呢?
-
asyncFn1(
function(){
-
//...
-
asyncFn2(
function(){
-
//...
-
asyncFn3(
function(){
-
//...
-
asyncFn4(
function(){
-
//...
-
asyncFn5(
function(){
-
//...
-
});
-
});
-
});
-
});
-
});
-
复制代码
有没有感觉头皮发麻?什么优雅什么可读性,瞬间荡然无存,这就是恐怖的“回调地狱”(Callback Hell)。
而我们发现,微信小程序的网络请求wx.request,也正是这种依靠回调函数的形式,类似于以前的$.ajax
,它在逻辑复杂、页面执行顺序要求多的情况下,弊端也是很明显的。不过好在小程序支持ES6,我们可以尽情地拥抱Promise!
使用Promise包装wx.request
Promise这东西简单说来就是,它可以将异步的执行逻辑和结果处理分离,摒弃了一层又一层的回调嵌套,使得处理逻辑更加清晰。想具体了解的还请自行查找资料。
现在我们就用Promise包装一下wx.request:
-
/**
-
* requestPromise用于将wx.request改写成Promise方式
-
* @param:{string} myUrl 接口地址
-
* @return: Promise实例对象
-
*/
-
const requestPromise =
myUrl => {
-
// 返回一个Promise实例对象
-
return
new
Promise(
(resolve, reject) => {
-
wx.request({
-
url: myUrl,
-
success:
res => resolve(res)
-
})
-
})
-
}
-
// 我把这个函数放在了utils.js中,这样在需要时可以直接引入
-
module.exports = requestPromise
-
复制代码
现在再使用试试:
-
// 引用模块
-
const utilApi =
require(
'../../utils/util.js')
-
Page({
-
...
-
// 生命周期函数onload用于监听页面加载
-
onLoad:
function () {
-
utilApi.requestPromise(
"https://www.bilibili.com/index/ding.json")
-
// 使用.then处理结果
-
.then(
res => {
-
console.log(res.data)
-
this.setData({
-
myData: res.data
-
})
-
console.log(
this.data.myData)
-
this.loadMyData()
-
})
-
}
-
})
-
复制代码
结果和使用回调函数一致。当有多个异步请求时,直接不断地.then(fn)去处理即可,逻辑清晰。
当然,这里只是写了一个最简单的Promise函数,还不完整。更完整的Promise化wx.request,等以后业务需要再完善吧。另外各种小程序开发框架也都有了现成的promise化API,拿来即用。