微信小程序踩坑系列——從wx.request談談異步處理

原文連接: https://www.xksblog.top/talk-...

見到wx.request的第一眼,就讓我想起了$.ajax這東西,使用起來確實有不少不方便,不能忍,幸虧小程序是支持ES6語法的,因此可使用promise稍加改造。html

先來講說wx.request爲何不能忍。ajax

鋪墊:「看得見卻抓不住「的異步請求

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()
  }
})

而後咱們會在控制檯到這樣的結果:json

這實際上是一個很簡單的異步問題,wx.request是異步請求,JS不會等待wx.request執行完畢再往下執行,因此JS按順序會先執行this.loadMyData(),等服務器返回數據之後,loadMyData()早就執行完了,固然也就沒有拿到值啦。小程序

其實咱們在同步流程中才說「返回」,異步沒有「返回」這個概念(或者說異步返回是沒有意義的),異步對應的是「回調」,也就是說,對於一個異步函數,咱們應該傳入一個「回調函數」來接收結果。微信小程序

初步解決:經過回調接收結果

最簡單的解決方案,就是把須要使用異步數據的函數寫在回調裏:api

...
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()
    }
  })
}

這樣就能夠正確輸出了:promise

可是若是邏輯複雜,須要多層異步操做,會出現怎麼樣的狀況呢?服務器

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,拿來即用。

相關文章
相關標籤/搜索