WeChat アプレット インターフェイスのカプセル化を実装することを約束する

hzc
リリース: 2020-06-15 10:55:12
転載
2638 人が閲覧しました

多くの開発者がコールバック地獄の問題に遭遇していると思います。 WeChat ミニプログラムの API は基本的にコールバック関数に基づいた非同期操作であるため、他のフレームワークやカプセル化された API を使用しない場合、特に wx.request() を多用する場合は、基本的にコールバック地獄の問題に遭遇することになります。メンテナンスはとても大変でした。

例:

現在、ソーシャル アプレットを開発しているとします。その機能の 1 つは、アプレットのユーザーがログイン後に近くの人々を表示できることです。

次の実装アイデアが使用されると仮定すると、wx.getLocation() を通じてユーザーの現在位置を取得し、wx.request() を通じてバックエンド データをリクエストします。以前の公式ドキュメントで推奨されているログイン方法を参照してください。まず wx.login() を呼び出してコードを取得し、次に wx.request() を使用して開発者サーバーにリクエストします。カスタム ログイン ステータスが正常に返された場合 (通常は access_token または他のトークン フォーム)、カスタム ログイン ステータスを使用してビジネス データをリクエストします。

読みやすいように、公式ドキュメントにログイン手順を掲載しました ⬇️

WeChat アプレット インターフェイスのカプセル化を実装することを約束する

アイデアが決まったら、コーディングを開始してください(実際にはそうではありません)次のコードを読むことをお勧めします)

/* 以下为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: ...
    }
  }) 
}
ログイン後にコピー

コールバック地獄が表示されます。気功波動コードは、ましてや他のものは見ているだけでも気分が悪くなるでしょう。

ある日、Yingming のプロダクト マネージャーが立ち上がって、XXXXX を追加できると言いました。他の WeChat インターフェイスをネストする場所を見つけるか、if else ブランチをいくつか追加する必要があるかもしれません。それなら泣く場所を見つけてください。

ソリューション

今日の嵐のようなフロントエンド エコシステムは、ある意味、Node と ES6 の出現に依存しています。

ES6 以降、非同期のソリューションは多数あります。 1 つは generator/yield を使用する方法ですが、generator 関数は実際には使用するのがより面倒です。もう 1 つは、Promise を使用する方法で、これは比較的単純です。 ES7 は async/await も使用できますが、ただし本質的に async/awaiPromise に基づいています。 お約束を以下に紹介します。

Promise


Promise の作成

Promise の作成は非常に簡単で、Promise 自体はコンストラクターです。新規経由で作成されました。コンストラクターのパラメーターはコールバック関数であり、コールバック関数には解決と拒否の 2 つのパラメーターがあります (手動メンテナンスは必要ありません)。状態を変更するには、resolve と raise を使用します。ステータスについては後ほどお話します。

// Promise实例的创建
let p = new Promise((resolve, reject) => {
  // TODO
})
ログイン後にコピー

Promise には欠点があり、作成されるとすぐに実行されてしまいます。したがって、通常は関数でラップされます。

let getPromise = () => {
  return new Promise((resolve, reject) => {
    // TODO    
  })
}
ログイン後にコピー

Promise ステータス

Promise インスタンスには、pendingresolved、および rejectedPromise# の 3 つの状態があります。 ##インスタンスが作成されると、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

() は 2 つのパラメータを受け取ることができ、どちらもコールバック関数です。最初のコールバック関数は

resolved 状態を処理するために使用され、パラメータは # です##Promise インスタンス呼び出しの解決によって渡された成功オブジェクト。 2 番目のコールバック関数は、rejected ステータスを処理するために使用され、パラメータは、Promise インスタンスを呼び出し、reject を呼び出すことによって渡されるエラー オブジェクトです。 実際にはthen()通常、解決された状況を処理するためにのみ使用します。つまり、最初のコールバック関数を渡すだけです。

rejected

の状況では、catch() を使用して均一に処理します。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">let getPromise = () =&gt; { return new Promise((resolve, reject) =&gt; { // TODO // 处理结果 if (result) { resolve(successObject) } else { reject(error) } }) } getPromise() .then(res => { console.log(res) // TODO }) .catch(err => { //TODO })</pre><div class="contentsignin">ログイン後にコピー</div></div>then() メソッドを使用すると、

return

によって新しい Promise を返し、引き続き Promise オブジェクトを返すことができます。 , 継続して継承することができます。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">getPromise() .then(res =&gt; { //第一层Promise console.log(res) // TODO return getPromise() ) .then(res =&gt; { // 第二层Promise console.log(res) // TODO }) .catch(err =&gt; { // TODO })</pre><div class="contentsignin">ログイン後にコピー</div></div>その他の一般的に使用されるメソッドには、Promise.all()

Promise.race()

などがあります。複数の Promise 結果を待つ必要がある場合に使用されます。どちらのメソッドも、Promise で構成されるオブジェクトの配列を受け取ります。 Promise.all() を使用する場合、すべての Promise オブジェクトが resolved Promise.all() である場合にのみ、状態は resolved になります。 Promise.race() で Promise オブジェクトを 1 つだけ 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链上操作就行了。

推荐教程:《微信小程序

以上がWeChat アプレット インターフェイスのカプセル化を実装することを約束するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:juejin.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート