1、同步与异步 在小程序中网络请求wx.request不像其他框架可以设置同步或异步,wx.request在小程序中只能是异步方式。 既然是异步方式,就不能用以下的方式获取网络数据: let data = wx.request({ url:'', header:{ appket:"" } }) 1 2 3 4 5 6 而应该使用回调函数来获取请求后的数据。 wx.request({ url:'', header:{ appket:"" }, success:function(res){ console.log(res) } }) 2、箭头函数 如果回调函数使用传统写法,即上述写法,在使用data里的数据是,this.data中的this指的并不是Page对象,所以这样无法获取data数据。通常做法是在回调函数外部用that来存储this: let that = this; wx.request({ url:'', header:{ appket:"" }, success:function(res){ console.log(that.data.test) } }) 而使用箭头函数,则可以不需要that来存储this,直接使用this就行: wx.request({ url:'', header:{ appket:"" }, success:(res) => { console.log(this.data.test) } }) 3、回调函数的嵌套 如果在一个函数里要调用一个异步函数,则一定要把一个回调函数作为该函数的参数。 比如一个函数getLatest()要根据index从服务器获取相应的latest对象,则应该把获取数据的操作放在回调里,然后把这个回调作为getLatest()的一个参数。 getLatest()函数定义: getLatest(sCallback) { this.request({ url: 'classic/latest', success: (data) => { // 如果不用箭头函数,this将指代不正确 let key = this._fullKey(data.index) wx.setStorageSync(key, data) this._setLatestIndex(data.index) sCallback(data) } }) } 其中request函数也是异步函数,因此sCallback要放在request函数的回调中。 request函数定义如下: request(params) { var that = this var url = this.baseRestUrl + params.url; if (!params.method) { params.method = 'GET'; } wx.request({ url: url, data: params.data, method: params.method, header: { 'content-type': 'application/json', 'appkey':config.appkey }, success: function (res) { // 判断以2(2xx)开头的状态码为正确 // 异常不要返回到回调中,就在request中处理,记录日志并showToast一个统一的错误即可 var code = res.statusCode.toString(); var startChar = code.charAt(0); if (startChar == '2') { //先判断params.success是否为空, //如果不为空,将res.data作为参数传入params.success params.success && params.success(res.data); } else { params.error && params.error(res); } }, fail: function (err) { params.fail && params.fail(err) } }); } getLatest()函数调用: getLatest((data)=>{ this._getLikeStatus(data.id, data.type) this.setData({ classic:data }) }) 该回调函数是用箭头函数写的。 总之,存在异步函数的嵌套时,外层函数的返回值或数据处理要放在内层函数的回调里,以此类推。 而使用Promise时就可以解决回调嵌套的问题,因为Promise保留了函数return的功能。 比如requset()是个异步函数,而getHotList()中调用了requset(),页面中又执行了getHotList()函数。因此用回调函数的写法应该有两层嵌套。下面用Promise实现: request()函数: request({url,data={},method='GET'}){ return new Promise((resolve, reject)=>{ this._request(url,resolve,reject,data, method) }) } _request(url,resolve, reject, data={}, method='GET'){ wx.request({ url:config.api_base_url + url, method:method, data:data, header:{ 'content-type':'application/json', 'appkey':config.appkey }, success:(res)=>{ const code = res.statusCode.toString() if (code.startsWith('2')){ resolve(res.data) } else{ reject() const error_code = res.data.error_code this._show_error(error_code) } }, fail:(err)=>{ reject() this._show_error(1) } }) } getHotList()调用request() getHotList() { return this.request({ url: 'book/hot_list' }) } 调用getHotList()函数: bookModel.getHotList() .then(res => { this.setData({ books:res }) }) 4、Promise与异步 实现异步的三种方式: (1)纯粹callback; (2)Promise; (3)async与await(ES2017) 目前来说,由于小程序暂时不支持async与await,所以Promise是小程序处理异步的最佳解决方案。即使支持async,它也只是Promise的语法糖,所以Promise是必须要学习的基础。 Promise相对于回调函数的优势: (1)解决了纯粹callback嵌套造成的回调地狱问题; 如果在success回调函数中再次进行异步操作,而在该异步操作的回调函数中再进行异步操作,就形成了异步嵌套,会使代码的可阅读性变得很差,造成“回调地狱”: wx.request{ url:'', header:{ appket:"" }, success:(res) => { wx.request({ success:(res) => { wx.request({ success:(res) => { } } }) } }) 在这里插入图片描述 当然如果只有一次回调,就没必要用Promise了。 let promise = new Promise((resolve, reject)) => { wx.request{ url:'', header:{ appket:"" }, success:(res) => { wx.request({ success:(res) => { wx.request({ success:(res) => { } } }) } }) promise.then((res) => { console.log(res) }) } (2)解决了回调函数剥夺函数return能力的问题; 通常异步函数中是不能return结果的,而Promise可以解决这个问题。 在这里插入图片描述 (3)使代码更具可读性; (4)实现多个异步等待合并; Promise是一个对象,不是函数,对象可以保存状态,而函数不行。 5、使用promise 参考Javascript:Promise对象基础 (1)构造Promise Promise构造器接受一个函数作为参数,这个函数有两个参数:resolve,reject,分别代表这个Promise实例成功之后的回调函数和失败之后的回调函数。 这里我们将一个异步函数getSystemInfo()作为Promise的参数。 const promise = new Promise((resolve, reject) => { wx.getSystemInfo({ success: (res) => { resolve(res) }, fail: (error) => { reject(error) } }) } }) (2)Promise 的状态 Promise有3种状态: Pending:进行中 Resolved(Fulfilled):已完成 Rejected:已失败 Promise状态的改变只有两种: Pending --> Resolved Pending --> Rejected 这意味着,一个Promise对象resolve之后,状态就一直停留在Resolved那里了,反过来reject也一样。 这种特点的结果是,Promise对象的状态改变之后,你再给它添加回调函数,这个函数也会执行。 这跟事件监听器很不一样 —— 你一旦错过某个事件,就没办法再捕获他了,除非这个事件再次发生。 (3).then() 和 .catch() .then() 接收两个回调函数作为参数,第一个是当promise变成成功状态的回调函数;第二个是当promise变成失败状态的回调函数。 const promise = new Promise((resolve, reject) => { wx.getSystemInfo({ success: (res) => { resolve(res) }, fail: (error) => { reject(error) } }) }) promise.then( (res) => { console.log(res) },(error) => { console.log(error) }) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 箭头函数简写: 在这里插入图片描述 Promise的精髓: Promise作为对象保存了调用异步函数的结果,不需要附带任何回调函数。什么时候需要取Promise中的异步结果时,才使用.then() 和 .catch()调用一步函数。 下面针对一个获取服务器数据的request()方法分别用回调形式和Promise来写: 在这里插入图片描述 当需要在其他函数中调用该request方法时: 在这里插入图片描述 (4)promise实现链式调用 不管是then方法还是catch方法返回的都是一个新的Promise实例,这意味着Promise可以链式调用then和catch,每一个方法的返回值作为下一个方法的参数。 下面要实现多次调用API,即链式调用API,分别是错误的和正确的Promise用法: 在这里插入图片描述 嵌套式的写法又跟回调函数的写法一样了,不能体现Promise的作用。而应该把.then()写在外面,下面的.then()会接收上面的.then()的结果并作为参数继续执行。 (5)Promise.all() 和 Promise.race() Promise.all() 接收一个Promise对象的数组作为参数,当这个数组里的所有Promise对象全部变为resolve的时候,该方法才resolve。 如果其中一个Promise对象为reject的话,则该方法为reject。 比如有三个异步操作,都是向服务器请求数据,返回的Promise对象分别是detail ,comments ,likeStatus 。 开始获取数据前显示loading,获取完隐藏loading,这就需要使用Promise.all() 方法: wx.showLoading() const bid = options.bid const detail = bookModel.getDetail(bid) const comments = bookModel.getComments(bid) const likeStatus = bookModel.getLikeStatus(bid) Promise.all([detail, comments, likeStatus]) .then(res => {//res是一个数组 this.setData({ book: res[0], comments: res[1].comments, likeStatus: res[2].like_status, likeCount: res[2].fav_nums }) wx.hideLoading() }) Promise.race() 使用方法和Promise.all一样,接收一个Promise对象数组为参数。 只要其中一个Promise对象变为Resolved或者Rejected状态,该方法返回,进行后面的处理。
https://blog.csdn.net/weixin_42195593/article/details/90550172