Maison  >  Article  >  interface Web  >  Pratique prometteuse pour implémenter l'encapsulation de l'interface de l'applet WeChat

Pratique prometteuse pour implémenter l'encapsulation de l'interface de l'applet WeChat

hzc
hzcavant
2020-06-15 10:55:122541parcourir

Je pense que de nombreux développeurs ont rencontré le problème de l'enfer des rappels. Étant donné que les API des mini-programmes WeChat sont essentiellement des opérations asynchrones basées sur des fonctions de rappel, si vous n'utilisez pas d'autres frameworks ou d'API encapsulées, surtout si vous utilisez beaucoup de wx.request(), vous rencontrerez essentiellement le problème du rappel de l'enfer. rapidement. Entretien C'était très pénible.

Par exemple

Supposons que vous développiez actuellement une applet sociale. L'une des fonctions est qu'après s'être connectés, les utilisateurs de l'applet peuvent voir les personnes à proximité.

En supposant que l'idée d'implémentation suivante soit utilisée, nous obtenons l'emplacement actuel de l'utilisateur via wx.getLocation(), puis demandons les données du backend via wx.request(). Mais avant cela, vous devez vous connecter. Reportez-vous à la méthode de connexion recommandée par le document officiel précédent. Appelez d'abord wx.login() pour obtenir le code, puis utilisez wx.request() pour demander au serveur du développeur si le code est disponible. l'état de connexion personnalisé est renvoyé avec succès (généralement access_token ou autre forme de jeton), puis utilisez l'état de connexion personnalisé pour demander des données commerciales.

Pour faciliter la lecture, j'ai publié le processus de connexion dans le document officiel ⬇️

Pratique prometteuse pour implémenter lencapsulation de linterface de lapplet WeChat

Une fois l'idée déterminée, commencez à essayer de coder (ce n'est pas recommandé de lire le code suivant) )

/* 以下为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: ...
    }
  }) 
}

Callback L'enfer est apparu. Les codes des vagues de Qigong, sans parler des autres, vous rendront malade même si vous les regardez.

Un jour, le sage chef de produit s'est levé et a dit que nous pouvions ajouter du XXXXX. Vous devrez peut-être trouver un endroit pour imbriquer d'autres interfaces WeChat ou ajouter quelques if else branches supplémentaires. pleurer.

Solution

Dans un sens, l'écosystème front-end orageux d'aujourd'hui repose sur l'émergence de Node et d'ES6+.

Il existe de nombreuses solutions pour l'asynchrone après ES6. La première consiste à utiliser generator/yield, mais la fonction generator est en réalité plus difficile à utiliser. L'autre consiste à utiliser Promise, ce qui est relativement simple. ES7 peut également adopter async/await, mais essentiellement async/await est également basé sur Promise. Présenté ci-dessous : Promise.

Promesse


Création d'une promesse

Créer une promesse est très simple. La promesse elle-même est un constructeur. Créé via new. Le paramètre du constructeur est une fonction de rappel, et la fonction de rappel a deux paramètres : résoudre et rejeter (aucune maintenance manuelle requise). la résolution et le rejet sont utilisés pour changer d’état. Je parlerai du statut plus tard.

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

La promesse a un inconvénient, elle sera exécutée immédiatement une fois créée. Il est donc généralement fourni avec une fonction.

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

Statut de la promesse

Les instances de promesse ont trois états, pending, resolved et rejected Une fois l'instance Promise créée, elle sera dans le pending. État. resolve et reject dans la fonction de rappel sont utilisés pour changer le statut de l'instance Promise. Lorsque resolve est appelé, l'instance Promise passe du statut pending à resolved, indiquant le succès. Lorsque reject est appelé, l'instance Promise passe du statut pending à rejected, indiquant un échec.

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

Méthodes courantes

Les méthodes les plus couramment utilisées sont then() et catch(). L'enfer des rappels peut être résolu en passant l'utilitaire du problème then(). .

Parmi eux, then() peut recevoir deux paramètres, qui sont tous deux des fonctions de rappel. La première fonction de rappel est utilisée pour gérer le statut resolved, et le paramètre est l'objet de réussite transmis par le. Promise résolution d'appel d'instance. La deuxième fonction de rappel est utilisée pour gérer le statut rejected, et le paramètre est l'objet d'erreur transmis en appelant l'instance Promise appelant reject.

En pratiquethen() nous ne l'utilisons généralement que pour gérer la situation résolue, c'est-à-dire ne transmettre que la première fonction de rappel. Pour les situations rejected, catch() est utilisé pour les gérer uniformément.

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

L'utilisation de la méthode then() peut continuer à renvoyer un objet Promise, qui peut être continuellement transmis à travers return un nouveau Promise.

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

Les autres méthodes couramment utilisées incluent Promise.all(), Promise.race(). Utilisé lorsque plusieurs Promise résultats doivent être attendus. Les deux méthodes reçoivent un tableau d'objets composé de Promise. Lors de l'utilisation de Promise.all(), ce n'est que lorsque tous les objets Promise sont dans l'état resolved Promise.all() que resolved. Lorsque Promise.race() n'a besoin que d'un seul objet Promise pour être resolved, son statut est résolu.

Plus de façons de lire les documents associés.

Encapsulation de l'interface du mini-programme


Appris les bases de Promise En encapsulant des opérations asynchrones et en utilisant des chaînes Promise, le problème de l'enfer de rappel peut être résolu.

Comme wx.request() est utilisé plus fréquemment, nous encapsulons d'abord 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链上操作就行了。

推荐教程:《微信小程序

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer