代码审查,异步调用的常见问题剖析
先来看一段代码,就是一小段而已:
export function loginWithWx() { wx.showLoading({ title: "登录中..." }); wx.login({ success: res => { wx.request({ url: `${apiRoot}wx/${res.code}`, method: "get", success: res => { const { data } = res; const jwt = app.globalData.jwt = data?.jwt; if (jwt) { wx.reLaunch({ url: "../index/index" }); wx.hideLoading(); } else { showMessage(data.message || "登录时发生错误"); wx.hideLoading(); } }, fail: res => { showMessage("请求超时,请稍后重试"); } }); wx.hideLoading(); }, fail: res => { console.log(res); } }); wx.hideLoading(); }
这段代码乍一看,似乎没毛病。但是稍微思考一下,就能发现问题了。
首先,最直观的问题:缩进太深。缩进最深的地方是 24 个空格,也就是 6 层。一般我们认为 3 层以内的缩进比较容易阅读,超过 3 层应该考虑使用“Extract Method”方法进行重构。
接下来,看外层逻辑:
wx.showLoading() wx.login() wx.hideLoading()
这是期望的执行顺序。
注意到 wx.login
是一个异步过程,所以实际上 hideLoading()
并不会等登录过程结束就关闭了加载提示。所以第 2 个问题是忽略了异步执行的顺序。
马上可以想到使用 wx.login()
的 complete
参数来解决:
wx.showLoading(); wx.login({ complete: () => wx.hideLoading() });
不过马上就引出了下一个问题:complete 还是太快!
为什么?我们再把内部的逻辑结构清理出来:
wx.login({ success: () => { wx.request({ success: () => { }, fail: () => { } }) }, fail: () => { } })
注意到 wx.request
仍然是一个异步过程,所以 wx.login
的 success
会立即结束,触发 complete
。而这时候 wx.request
可能还在等待服务器响应。
那么是不是应该把 wx.hideLoading()
放到内部逻辑中去?理论上来说,是的!
但实际情况是,内部逻辑分支较多,深次较深,既有同步逻辑,也有异步逻辑……考虑应该放在哪些地方,需要非常的谨慎。实际上,案例中的代码就已经在内部逻辑中放了一些 wx.hideLoading()
,只不过
- 覆盖不全;
- 因为最外层的
hideLoading()
提前执行,失效了。 - 违反了规范性约束:成对逻辑应该尽量避免一对多的情况。
解释一下第 3 点,就是说:一个 showLoading()
最好只对应一个 hideLoading()
。考虑到逻辑的复杂性,这不是强制约束规则,但应该尽量去避免。
处理的办法是,重构,将内部逻辑拆分出来;然后,将完成事件处理逻辑作为一个参数,一层层的往里传:
显然在当前的技术环境中,这并不是最优方案,还可以继续优化——反正都要封装,干脆封装成 Promise。然后通过 await
调用转换成同步语法,处理起来会轻松得多。封装的具体过程在前两篇文章中有详细的讲解,这里就不赘述了。总之,我们封装了 wx
的异步版本 awx
,在这里用就好:
export async function asyncLoginWithWx() { wx.showLoading({ title: "登录中..." }); try { return await internalProcess(); } catch (err) { showMessage("请求超时,请稍后重试"); } finally { wx.showLoading(); } // 把内部逻辑用个局部函数封装起来, // 主要是为了让 try ... catch ... 看起来清晰一些 async function internalProcess() { const { code } = await awx.login(); const { data } = awx.request({ url: `${apiRoot}wx/${code}`, method: "get", }); const jwt = app.globalData.jwt = data?.jwt; if (jwt) { wx.reLaunch({ url: "../index/index" }); } else { showMessage(data.message || "登录时发生错误"); } } }
喜欢此文,点个赞 ⇙
支持作者,赏个咖啡豆 ⇓
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
自动化运维工具Ansible-playbook详解和案例实战(四)
1、playbook-剧本介绍 playbooks是 一个不同于使用Ansible命令行执行方式的模式,其功能更强大灵活。简单来说,playbook是一个非常简单的配置管理和多主机部署系统,不同于任何已经存在的模式,可作为一个适合部署复杂应用程序的基础。Playbook可以定制配置,可以按照指定的操作步骤有序执行,支持同步和异步方式。值得注意的是playbook是通过YAML格式来进行描述定义的。 1.1、核心元素 hosts:执行的远程主机列表 tasks:任务,由模板定义的操作列表 variables:变量,内置变量或者自定义变量在playboook中调用 templates:模板,即 使用模板语法的文件;可替换模板中的变量并实现一些简单逻辑的而文件 handlers:处理器,和notify结合使用 ;当某条件满足时,触发执行的操作 tags:标签,指定某条件下,用于选择运行playbook中的部分代码。Ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常的长。此时,如果确信其没有变化,就可以通过tags跳过这些代码片段...
- 下一篇
阿里云视觉智能开放平台--人脸识别使用教程
概述 人脸人体识别技术是基于阿里云深度学习算法,结合图像或视频的人脸检测、分析、比对以及人体检测等技术,为您提供人脸人体的检测定位、人脸属性识别和人脸比对等能力。可以为开发者和企业提供高性能的在线API服务,应用于人脸AR、人脸识别和认证、大规模人脸检索、照片管理等各种场景。 Step By Step 1、服务开通,参考链接:阿里云视觉智能开放平台使用简明教程 2、目前主要提供三个方面的能力:人脸识别、人体识别、人脸对比,能力介绍 3、其中人脸识别、人体识别 目前主要是单个API的调用,不涉及多个API的协同调用,使用相对简单(实例仅选择一个API演示)。人脸对比涉及到人脸库、样本、图片等的操作,需要多个API的协同操作: 4、Code Sample 4.1 pom.xml <dependencies> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.4...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS7设置SWAP分区,小内存服务器的救世主