微信小程序wx.request異步解決方案
見(jiàn)到wx.request的第一眼,就讓我想起了$.ajax這東西,使用起來(lái)確實(shí)有很多不方便,不能忍,幸好小程序是支持ES6語(yǔ)法的,所以可以使用promise稍加改造。
先來(lái)說(shuō)說(shuō)wx.request為什么不能忍。
鋪墊:“看得見(jiàn)卻抓不住“的異步請(qǐng)求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Page({ data: { myData: '' }, // loadMyData函數(shù)用于打印myData的值 loadMyData () { console.log('獲取到的數(shù)據(jù)為:' + this.data.myData) }, // 生命周期函數(shù)onload用于監(jiān)聽(tīng)頁(yè)面加載 onload: function () { wx.request({ url: 'https://api', // 某個(gè)api接口地址 success: res => { console.log(res.data) this.setData({ myData: res.data }) console.log(this.data.myData) } }) // 調(diào)用之前的函數(shù) this.loadMyData() } }) |
這其實(shí)是一個(gè)很簡(jiǎn)單的異步問(wèn)題,wx.request是異步請(qǐng)求,JS不會(huì)等待wx.request執(zhí)行完畢再往下執(zhí)行,所以JS按順序會(huì)先執(zhí)行this.loadMyData(),等服務(wù)器返回?cái)?shù)據(jù)以后,loadMyData()早就執(zhí)行完了,當(dāng)然也就沒(méi)有拿到值啦。
其實(shí)我們?cè)谕搅鞒讨胁耪f(shuō)“返回”,異步?jīng)]有“返回”這個(gè)概念(或者說(shuō)異步返回是沒(méi)有意義的),異步對(duì)應(yīng)的是“回調(diào)”,也就是說(shuō),對(duì)于一個(gè)異步函數(shù),我們應(yīng)該傳入一個(gè)“回調(diào)函數(shù)”來(lái)接收結(jié)果。
初步解決:通過(guò)回調(diào)接收結(jié)果最簡(jiǎn)單的解決方案,就是把需要使用異步數(shù)據(jù)的函數(shù)寫(xiě)在回調(diào)里:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
... onload: function () { wx.request({ url: 'https://api', // 某個(gè)api接口地址 success: res => { console.log(res.data) this.setData({ myData: res.data }) console.log(this.data.myData) // 把使用數(shù)據(jù)的函數(shù)寫(xiě)在回調(diào)函數(shù)success中 this.loadMyData() } }) } |
這樣就可以正確輸出了:
但是如果邏輯復(fù)雜,需要多層異步操作,會(huì)出現(xiàn)怎么樣的情況呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
asyncFn1(function(){ //... asyncFn2(function(){ //... asyncFn3(function(){ //... asyncFn4(function(){ //... asyncFn5(function(){ //... }); }); }); }); }); |
有沒(méi)有感覺(jué)頭皮發(fā)麻?什么優(yōu)雅什么可讀性,瞬間蕩然無(wú)存,這就是恐怖的“回調(diào)地獄”(Callback Hell)。
而我們發(fā)現(xiàn),微信小程序的網(wǎng)絡(luò)請(qǐng)求wx.request,也正是這種依靠回調(diào)函數(shù)的形式,類(lèi)似于以前的$.ajax,它在邏輯復(fù)雜、頁(yè)面執(zhí)行順序要求多的情況下,弊端也是很明顯的。不過(guò)好在小程序支持ES6,我們可以盡情地?fù)肀romise!
使用Promise包裝wx.requestPromise這東西簡(jiǎn)單說(shuō)來(lái)就是,它可以將異步的執(zhí)行邏輯和結(jié)果處理分離,摒棄了一層又一層的回調(diào)嵌套,使得處理邏輯更加清晰。想具體了解的還請(qǐng)自行查找資料。
現(xiàn)在我們就用Promise包裝一下wx.request:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/** * requestPromise用于將wx.request改寫(xiě)成Promise方式 * @param:{string} myUrl 接口地址 * @return: Promise實(shí)例對(duì)象 */ const requestPromise = myUrl => { // 返回一個(gè)Promise實(shí)例對(duì)象 return new Promise((resolve, reject) => { wx.request({ url: myUrl, success: res => resolve(res) }) }) } // 我把這個(gè)函數(shù)放在了utils.js中,這樣在需要時(shí)可以直接引入 module.exports = requestPromise |
現(xiàn)在再使用試試:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// 引用模塊 const utilApi = require('../../utils/util.js') Page({ ... // 生命周期函數(shù)onload用于監(jiān)聽(tīng)頁(yè)面加載 onLoad: function () { utilApi.requestPromise("https://www.bilibili.com/index/ding.json") // 使用.then處理結(jié)果 .then(res => { console.log(res.data) this.setData({ myData: res.data }) console.log(this.data.myData) this.loadMyData() }) } }) |
結(jié)果和使用回調(diào)函數(shù)一致。當(dāng)有多個(gè)異步請(qǐng)求時(shí),直接不斷地.then(fn)去處理即可,邏輯清晰。
當(dāng)然,這里只是寫(xiě)了一個(gè)最簡(jiǎn)單的Promise函數(shù),還不完整。更完整的Promise化wx.request,等以后業(yè)務(wù)需要再完善吧。另外各種小程序開(kāi)發(fā)框架也都有了現(xiàn)成的promise化API,拿來(lái)即用。
第二部分:如何開(kāi)通一個(gè)小商店