Promise实践 实现微信小程序接口封装
相信很多开发者都遇到过回调地狱的问题。由于微信小程序的API基本都是基于回调函数的异步操作,如果不使用其他框架或者封装API,特别是使用较多的wx.request(),基本很快就会遇到回调地狱的问题,维护起来十分痛苦。
举个例子
假设此时在正在开发一个社交小程序,其中有一个功能的是,小程序用户在登录后,可以查看附近的人。
假设使用以下的实现思路,我们通过wx.getLocation()获取用户当前位置,然后通过wx.request()请求后端数据。但在此之前需要登录,参考之前官方文档推荐的登录方式,先调用wx.login()获取code,再用wx.request()请求开发者服务器,成功返回自定义登录态(一般为access_token或其他令牌形式),之后再用自定义登录态请求业务数据。
为了方便看,我把官方文档里的登录流程贴出来⬇️
思路确定后,开始尝试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: ... } }) }
回调地狱出现了。气功波代码,别说别人,就连自己看都会觉得恶心。
某天英明的产品经理站了出来,说我们可以加点XXXXX,你可能还得找个地方嵌套其他微信接口或者多加几个if else
分支,到时候就找个地方哭吧。
解决方案
从某种意义上来说,当今风暴式的前端生态,仰仗于Node以及ES6+的出现。
ES6后对于异步有多种解决方案。一种是采用generator/yield
,但generator
函数使用起来其实比较麻烦。另外一种是采用Promise
,相对比较简单。ES7也可以采用async/await,
但本质上async/awai
t也是基于Promise
。下面介绍Promise
。
Promise
Promise创建
创建Promise很简单,Promise本身是一个构造函数。通过new创建。构造函数的参数为一个回调函数,回调函数有两个参数为resolve和reject(无需手动维护)。resolve和reject是用来改变状态。关于状态放到后边讲。
// Promise实例的创建 let p = new Promise((resolve, reject) => { // TODO })
Promise有个缺点,一旦创建便会立刻执行。所以一般会用一个函数进行包装。
let getPromise = () => { return new Promise((resolve, reject) => { // TODO }) }
Promise状态
Promise实例有三种状态,pending
、resolved
和rejected
,Promise
实例创建后就会处于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
()的传递效用就可以解决回调地狱的问题。
其中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 })
使用then()
方法可以继续返回一个Promise
对象,通过return
一个新的Promise
,可以持续的向下传递。
getPromise() .then(res => { //第一层Promise console.log(res) // TODO return getPromise() ) .then(res => { // 第二层Promise console.log(res) // TODO }) .catch(err => { // TODO })
其他常用方法有诸如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) } }) }) }
基本框架就这样,我们可以进一步修改,比如请求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链上操作就行了。
推荐教程:《微信小程序》
Atas ialah kandungan terperinci Promise实践 实现微信小程序接口封装. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



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

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

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

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.

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.

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

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

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.
