微信小程序wx.request()异步处理及promise的使用和封装

时间:2024-03-07 10:54:59

微信小程序和服务器端的数据交互都是通过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){ }) 中进行编码,

但这种方式会使代码可读性更好,更易维护,

特别是页面需要有服务器端回传值才能继续执行的情况下编程更友好。

具体怎么用,还是要根据项目的实际情况做决定。