微信小程序和服務器端的數據交互都是通過wx.request()這個API函數來完成的,這是一個異步函數,其原型如下:
1 wx.request({ 2 url: 'https://www.tm.com/api/orders', 3 data: { 4 pageIndex: 1,
5 pageSize: 10
6 }, 7 header: { 8 'content-type': 'application/json' // 默認值
9 }, 10 success:function(res) { 11 console.log(res.data) 12 }, 13 fail:function(res) { 14 console.log(res.data) 15 }, 16 complete:function(res) { 17 console.log(res.data) 18 }, 19 })
接受服務器端傳回來的數據是通過回調函數success:function(res){ }來進行的,實際項目中一般是這樣的形式:
1 success:function(res) { 2 if(res.statusCode==200){ //一定要先判斷status==200再接收值,這是小程序的規則決定的。 3 let ret = res.data; 4 //其他操作
5 } 6 },
因為是異步函數,獲取服務器數據時會出現幾秒至幾十秒的延遲,
在渲染頁面的時候如果要用到服務器數據的可能獲取不到,
一個常用的解決方式是所有涉及到服務器數據的變量都要進行初始化,並且頁面加載的時候用loading提示,如下:
1 data:{
2 title: '購物車', amount: 0, // 初始化需要從服務端獲取值的變量
3 },
4 test:function(){
5 let _this = this; 6 wx.showLoading({ 7 title: '數據加載中...', 8 }) //頁面加載時用戶友好提示 9 wx.request({ 10 url: 'https://www.tm.com/api/orders', 11 data: {
12 pageIndex: 1, pageSize: 10
13 }, 14 header: { 15 'content-type': 'application/json' // 默認值
16 }, 17 success:function(res) { 18 if(res.statusCode=200){ 19 let orders = res.data; 20 //從服務器端取到值后用setData()函數更新變量值
21 _this.setData({title:orders.title});
22 _this.setData({amount:orders.amount});
23 // 其他操作
24 } 25 }, 26 fail:function(res) { 27 console.log("request error...") 28 }, 29 complete:function(res) { 30 wx.hideLoading(); //數據加載完成后關閉loading. 31 }, 32 }) 33
34 },
在有些情況下,我們需要根據服務器傳遞回來的值來做下一個操作的時候其代碼都要寫到success:function(res){ }函數中,
如果success:function(res){ } 中又要調用wx.request()就會碰到所謂的“回調地獄”,難以編碼和維護,
在小程序中可以用promise的方式來處理,部分異步API已經支持,在官方文檔上的描述是這樣的:
從基礎庫 2.10.2 版本起,異步 API 支持 callback & promise 兩種調用方式,官方文檔截圖如下:
但是很遺憾wx.request()還不支持promise這種方式,也就是說不能用wx.request().then()的方式來處理數據,
所以我們需要用promise對wx.request()來做封裝。
使用promise分兩步:
一 . 先構造 promise 對象,語法如下,Promise的構造函數用匿名函數 function(resolve, reject){ } 做參數,
匿名函數的 resolve 和 reject 參數是執行成功和失敗時要調用的函數:
1 let pro = new Promise(function(resolve, reject) { 2 //do something.
3 });
二 . 然后在then方法中傳入要回調的函數做下一步的處理,如下:
1 pro.then(resolve, reject);
其中第一個參數是resolve回調函數,表示任務完成要執行的方法,第二參數是reject回調函數,表示任務失敗要執行的方法。
其具體的使用方式還有如下幾種形式:
1 , 只有resolve沒有reject,可以這樣寫(reject參數可以省略):
pro.then(function (data){ //用匿名函數做參數
//do something
});
2 . 沒有resolve只有reject,必須這樣寫(resolve要用null占位,不能省略):
pro.then(null,function(err){ //用匿名函數做參數 //do something
});
三 . then函數返回的是一個新的promise對象,所以可以鏈式調用,如下:
1 pro.then(function (data){ }) 2 .then(function (data){ }) 3 .then(function (data){ });
四 . ES6標准中提供了catch函數來處理任務失敗時要執行的操作,相當於then(null, reject),如下:
1 pro.catch(function(err) { 2 //do something
3 });
這種寫法可讀性更好,更清晰。
有了上面的基礎知識,就可以封裝一個promise版本的wx.request()了,
考慮到這樣一個功能在小程序的很多地方都會用到,我們將其放到一個單獨的js文件中,
調用的時候引用這個js文件就可以了,在小程序的utils目錄中新建一個common.js的文件,如下:
common.js文件中的代碼如下:
1 const requestSync = (_url, _data, _method, _callcomplete)=>{ 2 let pro = new Promise(function(resolve, reject) { 3 wx.request({ 4 url: _url, 5 data:_data, 6 method:_method, 7 success:function(res){ 8 if(res.statusCode==200){ 9 console.log("wx.request() is success : 200 ok."); 10 resolve(res); //任務成功就執行resolve(),其他情況下都執行reject() 11 } 12 else{ 13 console.log("wx.request() is success : 200 lost."); 14 reject(res); //響應失敗就執行reject() 15 } 16 }, 17 fail:function(res){ 18 console.log("wx.request() is fail : "+ res.errMsg); 19 reject(res); //API執行失敗也執行reject() 20 }, 21 complete:function(res){ 22 console.log("wx.request() is complete ."); 23 if(_callcomplete) {_callcomplete(res);} //如果有回調函數在執行完成后要調用回調函數 24 } 25 }) 26
27 }); 28 return pro; 29 } 30
31 //暴露接口供外部調用
32 module.exports = { 33 requestSync: requestSync 34 }
小程序的.js頁面調用代碼如下:
1 const wx2 = require('../../utils/common.js') //添加引用
3 const app = getApp(); //獲取應用實例
4
5 Page({ 6 data: { 7 }, 8
9 helloTap:function(e){ 10 let url = "https://www.tm.com/api/orders"; 11 let data = {pageIndex:1}; 12 let pro = wx2.requestSync(url, data, "GET", null); //調用封裝后的方法 13 pro.then(function(res){ //任務成功執行的操作,對應Promise中的 resolve(res)函數 14 console.log("success:"+res.statusCode); 15 let data = res.data; 16 //do something...
17 }).catch(function(res){ //任務失敗執行的操作,對應Promise中的 reject(res)函數 18 console.log("error:"+res.errMsg); 19 wx.showToast({ 20 title: '系統出錯。'
21 }) 22 }); 23 }, 24
25 onLoad: function () { 26
27 }, 28
29 })
注 : 這里雖然用promise對wx.request()進行了封裝,但是本質還是異步處理,
要獲取服務器端傳回來的數據仍然需要將后續的代碼放到 pro.then(function(res){ }) 中進行編碼,
但這種方式會使代碼可讀性更好,更易維護,
特別是頁面需要有服務器端回傳值才能繼續執行的情況下編程更友好。
具體怎么用,還是要根據項目的實際情況做決定。