91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Promise實現微信小程序接口封裝過程

發布時間:2020-06-15 13:40:43 來源:億速云 閱讀:1910 作者:鴿子 欄目:web開發

相信很多開發者都遇到過回調地獄的問題。由于微信小程序的API基本都是基于回調函數的異步操作,如果不使用其他框架或者封裝API,特別是使用較多的wx.request(),基本很快就會遇到回調地獄的問題,維護起來十分痛苦。

舉個例子

假設此時在正在開發一個社交小程序,其中有一個功能的是,小程序用戶在登錄后,可以查看附近的人。

假設使用以下的實現思路,我們通過wx.getLocation()獲取用戶當前位置,然后通過wx.request()請求后端數據。但在此之前需要登錄,參考之前官方文檔推薦的登錄方式,先調用wx.login()獲取code,再用wx.request()請求開發者服務器,成功返回自定義登錄態(一般為access_token或其他令牌形式),之后再用自定義登錄態請求業務數據。

為了方便看,我把官方文檔里的登錄流程貼出來??

Promise實現微信小程序接口封裝過程

思路確定后,開始嘗試coding(以下代碼不建議看完)

/* 以下為Page對象的方法 */

getNearby: function() {
  // 判斷是否已認證,可采用wx.checkSession()方案
  if (isAuth) {
  // TODO: 獲取業務數據
    return
  }
  
  // wx.login獲取code
  wx.login({
    success(res) {
      if (res.code) {
      
      // 獲取自定義登錄態
      wx.request({
        url,
        method, 
        headers,
        data,
        success(res) {
          // 請求成功
          if (res.statuCode === 200) {
            // 讀取響應體中的自定義登錄態
            let token = res.data.token
            // 保存自定義登錄態
            wx.setStorageSync("assess_token", token)
            
            // 獲取位置信息
            wx.getLocation({
              success(res) {
                let { latitude, longitude } = res
                
                // 請求業務數據
                wx.request({
                  url, 
                  method, 
                  header,
                  data: { latitude, longitude },
                  success(res) {
                    // 請求成功
                    if (res.statuCode === 200) {
                      let data = res.data
                      // 數據渲染到V層
                      this.setData({ list: data })
                    }
                    // 請求失敗
                    else if (res.statuCode === 400) {
                      // TODO
                    }
                    // 其他錯誤情況狀態碼處理
                    // TODO
                  }, 
                  fail(err) {
                    // 調用失敗處理
                  }
                })
                
              },
              fail(err) {
                // 調用失敗處理
              }
            })
          }
          // 請求失敗
          else if (res.statuCode == 400) {
            // TODO
          }
          // 其他錯誤情況的狀態碼處理
          },
          fail(err) {
            // 調用失敗處理
          }
        })
      } 
      else {
        // TODO
        // 登錄失敗
      }
    }, 
    fail(err) {
      // wx.login()調用失敗處理
      // TODO: ...
    }
  }) 
}

回調地獄出現了。氣功波代碼,別說別人,就連自己看都會覺得惡心。

某天英明的產品經理站了出來,說我們可以加點XXXXX,你可能還得找個地方嵌套其他微信接口或者多加幾個if else分支,到時候就找個地方哭吧。

解決方案

從某種意義上來說,當今風暴式的前端生態,仰仗于Node以及ES6+的出現。

ES6后對于異步有多種解決方案。一種是采用generator/yield,但generator函數使用起來其實比較麻煩。另外一種是采用Promise,相對比較簡單。ES7也可以采用async/await,但本質上async/await也是基于Promise。下面介紹Promise

Promise


Promise創建

創建Promise很簡單,Promise本身是一個構造函數。通過new創建。構造函數的參數為一個回調函數,回調函數有兩個參數為resolve和reject(無需手動維護)。resolve和reject是用來改變狀態。關于狀態放到后邊講。

// Promise實例的創建
let p = new Promise((resolve, reject) => {
  // TODO
})

Promise有個缺點,一旦創建便會立刻執行。所以一般會用一個函數進行包裝。

let getPromise = () => {
  return new Promise((resolve, reject) => {
    // TODO    
  })
}

Promise狀態

Promise實例有三種狀態,pendingresolvedrejectedPromise實例創建后就會處于pending狀態。回調函數中的resolvereject就是用來改變Promise實例狀態的。當調用resolve時,Promise實例會從pending變成resolved狀態,表示成功。當調用reject時,Promise實例會從pending變成rejected狀態,表示失敗。

let getPromise = () => {
  return new Promise((resolve, reject) => {
    // TODO  
    // 處理結果
    if (result) {
      resolve(successObject)
    } 
    else {
      reject(error)
    }
  })
}

常用方法

最常用的方法為then()和catch()這兩個方法,通過then()的傳遞效用就可以解決回調地獄的問題。

其中then()可接收兩個參數,都是回調函數,第一個回調函數用來處理resolved狀態,參數為Promise實例調用resolve傳遞的成功對象。第二回調函數用來處理rejected狀態,參數為調用Promise實例調用reject傳遞的錯誤對象。

實際中then()我們一般只用來處理resolved的情況,即只傳遞第一個回調函數。對于rejected情況更多是采用catch()統一處理。

let getPromise = () => {
  return new Promise((resolve, reject) => {
    // TODO  
    // 處理結果
    if (result) {
      resolve(successObject)
    } 
    else {
      reject(error)
    }
  })
}

getPromise()
  .then(res => {
    console.log(res)
    // TODO
  })
  .catch(err => {
    //TODO
  })

使用then()方法可以繼續返回一個Promise對象,通過return一個新的Promise,可以持續的向下傳遞。

getPromise()
  .then(res => {	//第一層Promise
    console.log(res)
    // TODO
    return getPromise()
    )
  .then(res => {	// 第二層Promise
    console.log(res)
    // TODO
  })
  .catch(err => {
    // TODO
  })

其他常用方法有諸如Promise.all()Promise.race()。當需要等待多個Promise結果時會采用。兩個方法都是接收一個由Promise組成的對象數組。使用Promise.all()時,只有當全部的Promise對象全部resolved Promise.all()狀態才是resolved。而Promise.race()只需有一個Promise對象為resolved時,其狀態就為resolved。

更多方法可閱讀相關文檔。

封裝小程序接口


學習了Promise基礎,通過封裝異步操作,使用Promise鏈就可以解決回調地獄問題。

因為wx.request()使用頻率比較高,先對wx.request()封裝。

/* 可以將公用的方法掛在app.js中 */

request: function(method, url, header, data) {
  return new Promise((resolve, reject) => {
    wx.request({
      method, 
      url, 
      header, 
      data,
      success(res) {
        resolve(res)
      },
      fail(err) {
        reject(err)
      }
    })
  })
}

基本框架就這樣,我們可以進一步修改,比如請求url的基礎路徑,添加一些公用的header,針對狀態碼做一些全局處理等。

request: function(method, url, header = {}, data = {}) {
  // 啟動時可將storage中的令牌掛到app.js 
  let token = app.assess_token
  if (token) {
    header["Authorization"] = token
  }
  return new Promise((resolve, reject) => {
    wx.request({
      method, 
      url: "https://api.domain.com/v1" + url,
      header, 
      data,
      success(res) {
        // 請求成功
        if (res.statusCode === 200) {
          resolve(res)
        }
        // 請求成功無響應體
        else if (res.statusCode === 204) {
          /* 
          可做一些成功提示,
          如調用wx.showToast()、wx.showModal()或自定義彈出層等 
          */
          resolve(res)
        }
        // 未認證
        else if (res.statusCode === 401) {
          /* 可做一些錯誤提示,或者直接跳轉至登錄頁面等 */
          reject(res)
        }
        else if (res.statusCode == 400) {
        /* 可做一些錯誤提示*/
          reject(res)
        }
        else if (res.statuCode === 403) {
          /* 無權限錯誤提示*/
          reject(res)
        }
        // ...其他狀態碼處理
      },
      fail(err) {
        /* 可做一些全局錯誤提示,如網絡錯誤等 */
        reject(err)
      }
    })
  })
}

封裝之后,舉個例子,發送請求就可以修改為

/* 方法體中 */
let app = getApp()

app.request("POST", "/auth", {}, { username, password })	 
  .then(res => {  // 第一層請求
    // TODO 成功處理
    return app.request("GET", "/goods", {}, {})
  })
  .then(res => {	// 第二層請求
    // TODO 成功處理
    // 渲染視圖
  })
  .catch(err => {
    // TODO 錯誤處理
  })

封裝一下其他的微信接口

/* 可以將公用的方法掛在app.js中 */
wxLogin: function() {
  return new Promise((resovle, reject) => {
    wx.login({
      success(res) {
        if (res.code) {
          resovle(res)
        }
        else {
          reject({ message: "登錄失敗" })
        }
      },
      fail(err) {
        reject(err)
      }
    })
  })
}

getLocation: function() {
  return new Promise((resolve, reject) => {
    wx.getLocation({
      success(res) {
        resolve(res)
      },
      fail(err) {
        reject(err)
      }
    })
  })
}

對于最初的例子,可以就修改為

/* Page對象的方法 */

getNearby: function() { 
  // 判斷是否已認證,可采用wx.checkSession()方案
  if (isAuth) {
    // TODO: 獲取業務數據
    return
  }
  
  app.wxLogin()
    .then(res => {
      // 將code發送給開發者服務器,獲取自定義登錄態
      return app.request("POST", "/auth", {}, { code, res.code })
    })
    .then(res => {
      // 保存自定義登錄態
      setStorage("access_token", res.data.access_token)
      // TODO: 其他登錄成功操作...	
      return app.getLocation()
    })
    .then(({ latitude, longitude }) => {
      let url = "/nearby?latitude=" + latitude + "&longitude=" + longitude
      return app.request("GET", url)
    })
    .then(res => {
      // TODO: 數據處理
      let data = res.data
      // 渲染視圖層
      this.setData({ data })
    })
    .catch(err => {
      // TODO 錯誤處理
    })
    
}

之后若有需添加新的請求或者其他異步操作,直接在Promise鏈上操作就行了。

以上就是Promise實踐 實現微信小程序接口封裝的詳細內容,更多請關注億速云其它相關文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

寿光市| 台中市| 澄江县| 临清市| 都江堰市| 色达县| 宜章县| 利川市| 茌平县| 涞水县| 揭东县| 泗阳县| 枣强县| 无棣县| 尼玛县| 太谷县| 正阳县| 房产| 伊金霍洛旗| 德昌县| 静宁县| 永清县| 平和县| 应城市| 荣成市| 平江县| 汨罗市| 商河县| 安徽省| 寿阳县| 略阳县| 封丘县| 漯河市| 广宗县| 越西县| 安阳市| 迁西县| 金川县| 舞阳县| 永善县| 西城区|