多くの開発者がコールバック地獄の問題に遭遇していると思います。 WeChat ミニプログラムの API は基本的にコールバック関数に基づいた非同期操作であるため、他のフレームワークやカプセル化された API を使用しない場合、特に wx.request() を多用する場合は、基本的にコールバック地獄の問題に遭遇することになります。メンテナンスはとても大変でした。
例:
現在、ソーシャル アプレットを開発しているとします。その機能の 1 つは、アプレットのユーザーがログイン後に近くの人々を表示できることです。
次の実装アイデアが使用されると仮定すると、wx.getLocation() を通じてユーザーの現在位置を取得し、wx.request() を通じてバックエンド データをリクエストします。以前の公式ドキュメントで推奨されているログイン方法を参照してください。まず wx.login() を呼び出してコードを取得し、次に wx.request() を使用して開発者サーバーにリクエストします。カスタム ログイン ステータスが正常に返された場合 (通常は access_token または他のトークン フォーム)、カスタム ログイン ステータスを使用してビジネス データをリクエストします。
読みやすいように、公式ドキュメントにログイン手順を掲載しました ⬇️
アイデアが決まったら、コーディングを開始してください(実際にはそうではありません)次のコードを読むことをお勧めします)
/* 以下为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/awai
も Promise
に基づいています。 お約束
を以下に紹介します。
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 インスタンスには、pending
、resolved
、および rejected
、Promise# の 3 つの状態があります。 ##インスタンスが作成されると、
pending 状態になります。コールバック関数の
resolve と
reject は、
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
resolved 状態を処理するために使用され、パラメータは # です##Promise
インスタンス呼び出しの解決によって渡された成功オブジェクト。 2 番目のコールバック関数は、rejected
ステータスを処理するために使用され、パラメータは、Promise
インスタンスを呼び出し、reject
を呼び出すことによって渡されるエラー オブジェクトです。 実際には
then()
通常、解決された状況を処理するためにのみ使用します。つまり、最初のコールバック関数を渡すだけです。
の状況では、catch
() を使用して均一に処理します。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">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
})</pre><div class="contentsignin">ログイン後にコピー</div></div>
then()
メソッドを使用すると、
によって新しい Promise
を返し、引き続き Promise
オブジェクトを返すことができます。 , 継続して継承することができます。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">getPromise()
.then(res => { //第一层Promise
console.log(res)
// TODO
return getPromise()
)
.then(res => { // 第二层Promise
console.log(res)
// TODO
})
.catch(err => {
// TODO
})</pre><div class="contentsignin">ログイン後にコピー</div></div>
その他の一般的に使用されるメソッドには、Promise.all()
、
などがあります。複数の 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 サイトの他の関連記事を参照してください。