Rumah hujung hadapan web tutorial js Promise实践 实现微信小程序接口封装

Promise实践 实现微信小程序接口封装

Jun 15, 2020 am 10:55 AM
promise

相信很多开发者都遇到过回调地狱的问题。由于微信小程序的API基本都是基于回调函数的异步操作,如果不使用其他框架或者封装API,特别是使用较多的wx.request(),基本很快就会遇到回调地狱的问题,维护起来十分痛苦。

举个例子

假设此时在正在开发一个社交小程序,其中有一个功能的是,小程序用户在登录后,可以查看附近的人。

假设使用以下的实现思路,我们通过wx.getLocation()获取用户当前位置,然后通过wx.request()请求后端数据。但在此之前需要登录,参考之前官方文档推荐的登录方式,先调用wx.login()获取code,再用wx.request()请求开发者服务器,成功返回自定义登录态(一般为access_token或其他令牌形式),之后再用自定义登录态请求业务数据。

为了方便看,我把官方文档里的登录流程贴出来⬇️

28750a8cc0cf3bb67705f8fb097fa62.png

思路确定后,开始尝试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: ...
    }
  }) 
}
Salin selepas log masuk

回调地狱出现了。气功波代码,别说别人,就连自己看都会觉得恶心。

某天英明的产品经理站了出来,说我们可以加点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
})
Salin selepas log masuk

Promise有个缺点,一旦创建便会立刻执行。所以一般会用一个函数进行包装。

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

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)
    }
  })
}
Salin selepas log masuk

常用方法

最常用的方法为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
  })
Salin selepas log masuk

使用then()方法可以继续返回一个Promise对象,通过return一个新的Promise,可以持续的向下传递。

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

其他常用方法有诸如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)
      }
    })
  })
}
Salin selepas log masuk

基本框架就这样,我们可以进一步修改,比如请求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)
      }
    })
  })
}
Salin selepas log masuk

封装之后,举个例子,发送请求就可以修改为

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

app.request("POST", "/auth", {}, { username, password })	 
  .then(res => {  // 第一层请求
    // TODO 成功处理
    return app.request("GET", "/goods", {}, {})
  })
  .then(res => {	// 第二层请求
    // TODO 成功处理
    // 渲染视图
  })
  .catch(err => {
    // TODO 错误处理
  })
Salin selepas log masuk

封装一下其他的微信接口

/* 可以将公用的方法挂在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)
      }
    })
  })
}
Salin selepas log masuk

对于最初的例子,可以就修改为

/* 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 错误处理
    })
    
}
Salin selepas log masuk

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

推荐教程:《微信小程序

Atas ialah kandungan terperinci Promise实践 实现微信小程序接口封装. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Menepati janji anda: Kebaikan dan keburukan menunaikan janji anda Menepati janji anda: Kebaikan dan keburukan menunaikan janji anda Feb 18, 2024 pm 08:06 PM

Dalam kehidupan seharian, kita sering menghadapi masalah antara janji dan menunaikan. Sama ada dalam hubungan peribadi atau transaksi perniagaan, menunaikan janji adalah kunci untuk membina kepercayaan. Walau bagaimanapun, kebaikan dan keburukan komitmen sering menjadi kontroversi. Artikel ini akan meneroka kebaikan dan keburukan komitmen dan memberi beberapa nasihat tentang cara untuk mengekalkan kata-kata anda. Faedah yang dijanjikan adalah jelas. Pertama, komitmen membina kepercayaan. Apabila seseorang menepati kata-katanya, dia membuat orang lain percaya bahawa dia seorang yang boleh dipercayai. Kepercayaan adalah ikatan yang terjalin antara orang, yang boleh menjadikan orang lebih banyak

Apakah yang perlu saya lakukan jika saya menghadapi Uncaught (dalam janji) TypeError dalam aplikasi Vue? Apakah yang perlu saya lakukan jika saya menghadapi Uncaught (dalam janji) TypeError dalam aplikasi Vue? Jun 25, 2023 pm 06:39 PM

Vue ialah rangka kerja bahagian hadapan yang popular, dan pelbagai ralat serta masalah sering dihadapi semasa membangunkan aplikasi. Antaranya, Uncaught(inpromise)TypeError ialah jenis ralat biasa. Dalam artikel ini, kita akan membincangkan punca dan penyelesaiannya. Apakah itu Uncaught(inpromise)TypeError? Ralat Uncaught(inpromise)TypeError biasanya muncul dalam

Ketahui lebih lanjut tentang Promise.resolve() Ketahui lebih lanjut tentang Promise.resolve() Feb 18, 2024 pm 07:13 PM

Penjelasan terperinci Promise.resolve() memerlukan contoh kod khusus Promise ialah mekanisme dalam JavaScript untuk mengendalikan operasi tak segerak. Dalam pembangunan sebenar, selalunya perlu untuk memproses beberapa tugas tak segerak yang perlu dilaksanakan mengikut turutan, dan kaedah Promise.resolve() digunakan untuk mengembalikan objek Promise yang telah dipenuhi. Promise.resolve() ialah kaedah statik kelas Promise, yang menerima a

Contoh analisis prinsip dan penggunaan Janji ES6 Contoh analisis prinsip dan penggunaan Janji ES6 Aug 09, 2022 pm 03:49 PM

Gunakan objek Promise untuk menukar fungsi biasa untuk mengembalikan Promise untuk menyelesaikan masalah panggilan balik neraka. Fahami logik panggilan kejayaan dan kegagalan Promise dan buat pelarasan secara fleksibel. Fahami pengetahuan teras, gunakannya dahulu, dan perlahan-lahan integrasikan dan serap pengetahuan.

Apakah objek janji? Apakah objek janji? Nov 01, 2023 am 10:05 AM

Keadaan objek janji adalah: 1. belum selesai: keadaan awal, bukan keadaan kejayaan atau kegagalan 2. dipenuhi: bermakna operasi berjaya diselesaikan 3. ditolak: bermakna operasi gagal. Setelah objek Promise selesai, ia akan berubah daripada keadaan belum selesai kepada keadaan dipenuhi atau ditolak, dan tidak boleh berubah lagi. Objek janji digunakan secara meluas dalam JavaScript untuk mengendalikan operasi tak segerak seperti permintaan AJAX dan operasi bermasa.

Penyemak imbas manakah yang menyokong Promise? Penyemak imbas manakah yang menyokong Promise? Feb 19, 2024 pm 04:41 PM

Keserasian penyemak imbas: Penyemak imbas manakah yang menyokong Promises? Memandangkan kerumitan aplikasi web terus meningkat, pembangun tidak sabar-sabar untuk menyelesaikan masalah pengaturcaraan tak segerak dalam JavaScript. Pada masa lalu, pembangun sering menggunakan fungsi panggil balik untuk mengendalikan operasi tak segerak, tetapi ini mengakibatkan kod yang rumit dan sukar untuk dikekalkan. Untuk menyelesaikan masalah ini, ECMAScript6 memperkenalkan Promise, yang menyediakan cara yang lebih intuitif dan fleksibel untuk mengendalikan operasi tak segerak. Janji ialah kaedah yang digunakan untuk mengendalikan pengecualian

Apakah kelebihan fungsi PHP yang mengembalikan objek Promise? Apakah kelebihan fungsi PHP yang mengembalikan objek Promise? Apr 19, 2024 pm 05:03 PM

Kelebihan: tak segerak dan tidak menyekat, tidak menyekat benang utama meningkatkan kebolehbacaan kod dan mekanisme pengendalian ralat;

Satu artikel akan membantu anda menguasai Promise dengan mudah Satu artikel akan membantu anda menguasai Promise dengan mudah Feb 10, 2023 pm 07:49 PM

Dalam pembelajaran js bahagian hadapan, perkara yang paling tidak selesa untuk semua orang ialah masalah asynchronousness Untuk menyelesaikan masalah seperti asynchronous dan callback hell, anda mesti belajar janji Bagi kebanyakan pengaturcara bahagian hadapan, janji hanyalah mimpi ngeri dari Sudut yang mudah difahami digunakan sebagai pintu masuk untuk membantu semua orang menguasai janji dengan mudah.

See all articles