wx.request封裝解決回調地獄(轉載)

原文鏈接:www.xksblog.top/talk-about-…

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

先來說說wx.request爲什麼不能忍。

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

  1. Page({
  2. data: {
  3. myData: ''
  4. },
  5. // loadMyData函數用於打印myData的值
  6. loadMyData () {
  7. console.log('獲取到的數據爲:' + this.data.myData)
  8. },
  9. // 生命週期函數onload用於監聽頁面加載
  10. onload: function () {
  11. wx.request({
  12. url: 'https://api', // 某個api接口地址
  13. success: res => {
  14. console.log(res.data)
  15. this.setData({
  16. myData: res.data
  17. })
  18. console.log(this.data.myData)
  19. }
  20. })
  21. // 調用之前的函數
  22. this.loadMyData()
  23. }
  24. })
  25. 複製代碼

然後我們會在控制檯到這樣的結果:

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

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

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

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

  1. ...
  2. onload: function () {
  3. wx.request({
  4. url: 'https://api', // 某個api接口地址
  5. success: res => {
  6. console.log(res.data)
  7. this.setData({
  8. myData: res.data
  9. })
  10. console.log(this.data.myData)
  11. // 把使用數據的函數寫在回調函數success中
  12. this.loadMyData()
  13. }
  14. })
  15. }
  16. 複製代碼

這樣就可以正確輸出了:

但是如果邏輯複雜,需要多層異步操作,會出現怎麼樣的情況呢?

  1. asyncFn1(function(){
  2. //...
  3. asyncFn2(function(){
  4. //...
  5. asyncFn3(function(){
  6. //...
  7. asyncFn4(function(){
  8. //...
  9. asyncFn5(function(){
  10. //...
  11. });
  12. });
  13. });
  14. });
  15. });
  16. 複製代碼

有沒有感覺頭皮發麻?什麼優雅什麼可讀性,瞬間蕩然無存,這就是恐怖的“回調地獄”(Callback Hell)。

而我們發現,微信小程序的網絡請求wx.request,也正是這種依靠回調函數的形式,類似於以前的$.ajax,它在邏輯複雜、頁面執行順序要求多的情況下,弊端也是很明顯的。不過好在小程序支持ES6,我們可以盡情地擁抱Promise!

使用Promise包裝wx.request

Promise這東西簡單說來就是,它可以將異步的執行邏輯和結果處理分離,摒棄了一層又一層的回調嵌套,使得處理邏輯更加清晰。想具體瞭解的還請自行查找資料。

現在我們就用Promise包裝一下wx.request:

  1. /**
  2. * requestPromise用於將wx.request改寫成Promise方式
  3. * @param:{string} myUrl 接口地址
  4. * @return: Promise實例對象
  5. */
  6. const requestPromise = myUrl => {
  7. // 返回一個Promise實例對象
  8. return new Promise((resolve, reject) => {
  9. wx.request({
  10. url: myUrl,
  11. success: res => resolve(res)
  12. })
  13. })
  14. }
  15. // 我把這個函數放在了utils.js中,這樣在需要時可以直接引入
  16. module.exports = requestPromise
  17. 複製代碼

現在再使用試試:

  1. // 引用模塊
  2. const utilApi = require('../../utils/util.js')
  3. Page({
  4. ...
  5. // 生命週期函數onload用於監聽頁面加載
  6. onLoad: function () {
  7. utilApi.requestPromise("https://www.bilibili.com/index/ding.json")
  8. // 使用.then處理結果
  9. .then(res => {
  10. console.log(res.data)
  11. this.setData({
  12. myData: res.data
  13. })
  14. console.log(this.data.myData)
  15. this.loadMyData()
  16. })
  17. }
  18. })
  19. 複製代碼

結果和使用回調函數一致。當有多個異步請求時,直接不斷地.then(fn)去處理即可,邏輯清晰。

當然,這裏只是寫了一個最簡單的Promise函數,還不完整。更完整的Promise化wx.request,等以後業務需要再完善吧。另外各種小程序開發框架也都有了現成的promise化API,拿來即用。

轉載於:https://juejin.im/post/5bac8e866fb9a05cf23001fe

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章