相信很多开发者都遇到过回调地狱的问题。由于微信小程序的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/await也是基于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链上操作就行了。

推荐教程:《微信小程序》

小程序php接口封装,Promise实践 实现微信小程序接口封装相关推荐

  1. 微信小程序周报(第十期)-微信小程序联盟

    每周一笑 程序猿:我的第一个问题是,对于我第二个和第三个问题,你可不可以只用'能'和'不能'来回答? 老板:"OK!" 我的第二个问题是,如果我的第三个问题是我能不能涨工资?那么你 ...

  2. 微信小程序:强大多流量主自带接口短视频去水印工具箱微信小程序

    这是一款强大的去水印组合的微信小程序源码 内已被小编支持多种热门流量主 如:激励视频,插屏,视频广告等等 激励视频解锁下载无水印小视频,图集等 另外功能也是特别的强大,如下: 短视频去水印(几十家平台 ...

  3. 小程序源码:强大多流量主自带接口短视频去水印工具箱微信小程序

    这是一款强大的去水印组合的微信小程序源码 内已被小编支持多种热门流量主 如:激励视频,插屏,视频广告等等 激励视频解锁下载无水印小视频,图集等 另外功能也是特别的强大,如下: 短视频去水印(几十家平台 ...

  4. 小程序api 分享scene_网课查题题库接口API-在线免费授权,微信小程序网课答案api接口...

    网课查题题库接口API-在线免费授权,微信小程序网课答案api接口更多相关问题 支持员工实现绩效目标.促进员工自身发展的能力标准的目标是().A.组织目标B.部门目标C.发展目标B.化肝煎合左金丸C. ...

  5. 《微信小程序开发实战》学习笔记chapter1微信小程序人门

    Chapter01 微信小程序入门 1. 微信小程序介绍 1.1 什么是微信小程序 微信小程序是腾讯于2017年1月19日推出的一种不需要安装即可在微信平台上使用的应用.微信小程序和微信的原生功能应用 ...

  6. 微信小程序上传图片到服务器总是失败_微信小程序怎么上传图片到服务器?

    微信小程序怎么上传图片到服务器?相信很多人都会把小程序图片保存到本地吧,但是把图片上传到服务器就不一定了,下面一起随小编看看微信小程序怎么上传图片到服务器吧. 微信小程序怎么上传图片到服务器? 首先, ...

  7. 微信小程序之仿淘宝分类入口 —— 微信小程序实战商城系列(2)

    分类入口,已经成为了商城项目必须的布局之一,这里以仿照淘宝的分类入口来做案例 下图红框部分,就是本文重点讲解部分,另外本文并没有写点击某个入口跳转页面. 如需学习页面跳转的同学,可以参考此文 微信小程 ...

  8. 微信小程序python解析获取用户手机号_微信小程序获取用户手机号

    获取微信用户绑定的手机号,需先调用wx.login接口. 小程序获取code. 后台得到session_key,openid. 组件触发getPhoneNumber 因为需要用户主动触发才能发起获取手 ...

  9. 微信小程序:王者荣耀战力查询微信小程序源码下载支持安卓苹果微信QQ等多区查询

    这是一款战力查询的微信小程序源码 源码内自带了接口 目前支持了微信,QQ,苹果,安卓全区都可以查询 支持流量主收益,而且搭建安装简单 使用微信开发者工具打开源码然后设置一下合法域名上传审核即可 该小程 ...

最新文章

  1. Android 白天/夜间模式切换
  2. 武汉大学提出ARGAN:注意力循环生成对抗模型用于检测、去除图像阴影 | ICCV 2019...
  3. 神经网络迭代次数与Lambert定律
  4. 【通信原理】【实验】实验三: 数字调制解调实验2ASK--2FSK--2PSK思路(GZHU)
  5. pat 1025 反转链表
  6. 软件工程设计之四则运算
  7. 需求管理-需求的结构
  8. 2014华为机试西安地区B组试题
  9. 大学数学实验习题--统计推断 03(附答案)
  10. python第三方库:使用Jieba对抓取的数据进行中文分词
  11. 开启和关闭android移动网络
  12. 主元分析法 matlab,数值分析实习作业之不选主元法高斯分解(Matlab)
  13. PowerPoint!让教学更精彩:PPT课件高效制作
  14. 第5篇-分析北京租房的房源信息
  15. 【数据治理】数据治理标准化白皮书 (2021 年)
  16. 场景文字检测之CTPN
  17. 永信至诚发起亿元创投基金 助力网络安全创业者成长
  18. Unity实战之见缝插针
  19. 高校实验室综合管理系统:建立一个安全、智慧、规范的实验室
  20. 远古vod5.0的安装!

热门文章

  1. (二)unity自带的着色器源码剖析之——————UnityCG.cginc文件(上篇:数学常数、颜色空间常数和函数、顶点布局格式结构体、进行空间变换的函数、HDR级光照贴图编解码相关函数等)
  2. Word、Excel、PPT题库——“办公自动化”
  3. 车路协同云控平台建设实践
  4. 一份Netty最全面试题!让面试官难不倒你!
  5. 第一回 甲骨文字始流传
  6. 最全Python培训课程,基础班+高级就业班+课件(数据分析、深度学习、爬虫、人工智能等) 精品课程
  7. linux中wget未找到命令
  8. 移动端 开源低代码工具 beeware 和 kivy
  9. 我的世界基岩服务器怎么弄虚拟玩家,【特别的】【新】服务器招各种技术工和玩家(基岩服)...
  10. 163邮箱注册申请哪个好?163邮箱如何处理垃圾邮件?