当前位置: 首页 > news >正文

uniapp 网络请求自动处理loading

文章目录

  • 背景
  • 整理思路
  • V1版本
  • V2版本
  • V3版本

背景

最近在写uniapp,发现执行网络请求的时候经常要处理Loading效果。

比如,在发送网络请求之前,触发Loadng;无论请求成功还是失败都要关闭Loading;请求失败的时候我们还要给用户一个友好的提示,比如“服务器打了个盹”。

每次都要手动处理,真的很麻烦;而且处理Loading的逻辑跟业务逻辑混在一起,也不便于维护。

因此,我打算把这个需求封装成要一个方法,就叫loadingRun

这个方法并不是一蹴而就的,经历了几个版本的迭代。我强烈建议你看完这篇文章,你一定能有所收获。

虽然是以uniapp代码演示的,但是思路是通用的。

整理思路

在封装之前,我们先看看封装之前代码长啥样:

uni.showLoading({mask: true})
uniCloud.database().collection('orders').doc(props.orderId).get({getOne: true}).then(res => {Object.assign(order, res.result.data)uni.hideLoading()
}).catch(_ => {uni.hideLoading().then(_ => uni.showToast({icon: "fail",title: "服务器打了个盹"}))
}).finally(_ => uni.hideLoading())

有些小伙伴可能不熟悉uniapp,所以我们解释一下部分代码:

  • uniCloud.database().collection('orders').doc(props.orderId).get({getOne: true})这是uniapp的uniCloud的操作,执行的是网络请求,返回的是一个promise。
  • uni.showLoading() uniapp 提供的显示Loading的api。
  • uni.hideLoading() uniapp 提供的关闭Loading的api。
  • uni.showToast() uniapp 提供的显示Toast提示api。

这些你都可以想象成自己熟悉的UI框架的操作。

我们需要把这个方法抽成一个通用的loadingRun方法,首先不管三七二十一,我们先把这个方法写出来:

function loadingRun() {uni.showLoading({mask: true})uniCloud.database().collection('orders').doc(props.orderId).get({getOne: true}).then(res => {Object.assign(order, res.result.data)uni.hideLoading()}).catch(_ => {uni.hideLoading().then(_ => uni.showToast({icon: "fail",title: "服务器打了个盹"}))}).finally(_ => uni.hideLoading())
}

然后我们就想,有哪些操作是可以提取出来,作为loadingRun的参数。
最容易想到的就是Object.assign(order, res.result.data)这行代码,这行代码是promise解决之后处理逻辑,我们可以把它提取成一个resolve参数:

function loadingRun(resolve) {uni.showLoading({mask: true})uniCloud.database().collection('orders').doc(props.orderId).get({getOne: true}).then(res => {resolve(res)uni.hideLoading()}).catch(_ => {uni.hideLoading().then(_ => uni.showToast({icon: "fail",title: "服务器打了个盹"}))}).finally(_ => uni.hideLoading())
}

还有什么可以提取的呢?uniCloud.database().collection('orders').doc(props.orderId).get({getOne: true})这个操作我们可以提取,因为的网络操作是不固定的。它是一个promise,我们先不管三七二十一,先用一promise来接收:

function loadingRun(promise, resolve) {uni.showLoading({mask: true})promise.then(res => {resolve(res)uni.hideLoading()}).catch(_ => {uni.hideLoading().then(_ => uni.showToast({icon: "fail",title: "服务器打了个盹"}))}).finally(_ => uni.hideLoading())
}

还能再抽吗?貌似toast提醒的文案可以抽出来,不过我们整站的提示都是统一的,所以就不抽了。

现在就可以了吗?显然不是,它还有问题,有大问题,我们接着聊。

V1版本

我们前面讲了封装loadingRun的思路,就是“抽”、“抽”、“抽”,先不管合理不合理,先抽再说。这样可以让我们最快的得到一个基本的骨架:

function loadingRun(promise, resolve) {uni.showLoading({mask: true})promise.then(res => {resolve(res)uni.hideLoading()}).catch(_ => {uni.hideLoading().then(_ => uni.showToast({icon: "fail",title: "服务器打了个盹"}))}).finally(_ => uni.hideLoading())
}

看着不错,实际有大问题,你知道是啥问题吗?

问题就是loadingRun直接接收了一个promise实例。

为啥直接接收就有问题呢?因为promise是创建时立即执行的,所以loadingRun执行的时候,promise可能已经执行完了,网络请求可能都返回了,此时在才显示Loading,黄瓜菜都凉了。

所以loadingRun不能从外部接收一个promise,我们需要在loadingRun内部创建这个promise。
我们可以让外部传入一个方法promiseGenerator,这个方法执行会产生一个promise:

function loadingRun(promiseGenerator, resolve) {uni.showLoading({mask: true})promiseGenerator().then(res => {resolve(res)uni.hideLoading()}).catch(_ => {uni.hideLoading().then(_ => uni.showToast({icon: "fail",title: "服务器打了个盹"}))}).finally(_ => uni.hideLoading())
}

至此我们获得了V1版本的loadingRun,我们前面代码可以用loadingRun来重构一下:

loadingRun(_ => uniCloud.database().collection('orders').doc(props.orderId).get({getOne: true}), res => Object.assign(order, res.result.data))

看起来没那么清晰对吧,我们再改进一下:

// 把获取订单的操作封装到一个方法中
function getOrderAsync(id) {return uniCloud.database().collection('orders').doc(id).get({getOne: true})
}
// 封装处理逻辑
function reactiveSetOrder(res) {Object.assign(order, res.result.data)
}

现在的loadingRun就清晰了:

loadingRun(getOrderAsync(props.id), reactiveSetOrder)

当然后面这个封装,不属于我门今天讨论的范畴。

V2版本

什么,还有V2版本,loadingRun还可以再优化吗?

还真是!现在的loadingRun接收一个promiseGeneratorpromiseGenerator产生一个promise实例。

如果我有一个很耗时的方法,但是它不返回promise,它也想用loadingRun怎么办呢?

现在V1版本还不够通用,我们需要让它变得更加通用。

我们可以这么处理,我们把promiseGenerator参数,换成更通用的func参数。如果它的结果是一个promise,那么就走原来的逻辑;否则,我们把func的执行结果用Promise.resolve封装成一个promise,走之前的逻辑。

这个叫参数归一化!

我们先定一个方法判断变量是不是一个promise:

function isPromiseLike(value) {return value != null && (typeof value === 'object' || typeof value === 'function')&& typeof value.then === 'function'
}

这里并不是直接用instanceof Promise判断,而是判断变量是不是满足Promise A+规范。

接下来我们改造loadingRun

function loadingRun(func, resolve) {uni.showLoading({mask: true})let ret = func()let promise = isPromiseLike(ret) ? ret : Promise.resolve(ret)promise.then(res => {resolve(res)uni.hideLoading()}).catch(_ => {uni.hideLoading().then(_ => uni.showToast({icon: "fail",title: "服务器打了个盹"}))}).finally(_ => uni.hideLoading())
}

现在我们可以用loadingRun处理耗时的非promise操作了,比如计算斐波那契数列:

loadingRun(_ => fibonacciRecursive(100000), val => console.log(`计算结果:${val}`))

V3版本

啊!还能再优化吗?

还真实。现在的loadingRun已经够用了,但是还有一个场景满足不了。

比如,当网络请求或者耗时操作报错了,我希望除了提示Toast,还要执行一个其他的操作,现在就没办法,因为promise实例没有返回出来。

因此改造也很简单,只需要把promise返回出来就行了。

function loadingRun(func, resolve) {uni.showLoading({ mask: true })let ret = func()let promise = isPromiseLike(ret) ? ret : Promise.resolve(ret)promise.then(res => {resolve(res)uni.hideLoading()}).catch(_ => {uni.hideLoading().then(_ => uni.showToast({icon: "fail",title: "服务器打了个盹"}))}).finally(_ => uni.hideLoading())return promise
}

然后我们就可以这样处理:

loadingRun(getOrderAsync(props.id), reactiveSetOrder).catch(_ => doSomething())

Game Over !!!

相关文章:

uniapp 网络请求自动处理loading

文章目录 背景整理思路V1版本V2版本V3版本 背景 最近在写uniapp,发现执行网络请求的时候经常要处理Loading效果。 比如,在发送网络请求之前,触发Loadng;无论请求成功还是失败都要关闭Loading;请求失败的时候我们还要…...

【Solidity】函数的使用

构造函数 构造函数仅在部署合约时调用一次,它的作用主要是初始化一些状态变量。 contract Demo {address public owner;uint public num;constructor(uint _num) {owner msg.sender;num _num;} }函数装饰器 函数装饰器可以在函数执行之前或之后插入代码逻辑&am…...

详解golang内存管理

介绍 要搞明白 Go 语言的内存管理,就必须先理解操作系统以及机器硬件是如何管理内存的。因为 Go 语言的内部机制是建立在这个基础之上的,它的设计,本质上就是尽可能的会发挥操作系统层面的优势,而避开导致低效情况。 操作系统内存管理 其实现在计算机内存管理的方式都是…...

C++ 线程 一些同步方式

C 线程一些同步方式 1.互斥锁(Mutex)2. 读写锁(Reader-Writer Lock)3. 信号量(Semaphore)4. 原子操作(Atomic)5. 屏障(Barrier)6. 条件变量(Condi…...

【开发语言】编译型语言和解释性语言有啥区别?

作为一名从业多年的程序员,对于编译型语言和解释型语言之间的区别有着深入的理解。这两种类型的编程语言在将源代码转换成可执行代码的过程中采用了不同的机制,这导致了它们在执行效率、跨平台性、安全性以及开发效率等方面存在一些差异。 编译型语言(Compiled Languages)…...

将A服务器上指定文件夹中的文件,批量同步到B服务器上

需求:最近有一个需求,需要定期将A服务器上的PDF文件,同步到B服务器上,于是便写个脚本记录一下! 下面是使用Python3脚本实现的方法 import os import paramikodef copy_pdf_files(source_ip, source_user, source_pas…...

2024.8.17

130124202408171002 DATE #:20240817 ITEM #:DOC WEEK #:SATURDAY DAIL #:捌月拾肆 TAGS < BGM "快哉风 -- 黄金玉米王" > < theme oi-language > < theme oi-graph theory > < [空] > < [空] >取次花丛懒回顾&#xff0c;半缘修道…...

十分钟搭建一个RTMP服务器

使用SRS搭建RTMP服务器 如果您需要搭建一个RTMP服务器&#xff0c;您可以使用SRS&#xff08;Simple-RTMP-Server&#xff09;来完成此任务。SRS是一个开源的RTMP服务器下面是一个简单的步骤指南&#xff1a; 获取srs srs官⽹&#xff1a;https://github.com/ossrs/srs 码云…...

Spring Boot解决循环注入问题

Spring Boot解决循环依赖注入问题 代码问题回显启动错误日志解决方案&#xff1a;使用事件驱动或通过 ApplicationContext 手动获取 Bean1. 事件驱动设计2. 使用 ApplicationContext 手动获取 Bean3. 拆分逻辑 总结 代码问题回显 现有代码1 在InterestService中依赖MemberInte…...

《数据挖掘》期末考核重点

1.数据预处理的目的与形式 数据预处理的目的是提供干净&#xff0c;简洁&#xff0c;准确的数据&#xff0c;以达到简化模型和提高算法泛化能力的目的&#xff0c;使挖掘过程更有效&#xff0c;更容易&#xff0c;提高挖掘效率和准确性。 2.数据预处理的形式 数据清理&#…...

Golang | Leetcode Golang题解之第334题递增的三元子序列

题目&#xff1a; 题解&#xff1a; func increasingTriplet(nums []int) bool {n : len(nums)if n < 3 {return false}first, second : nums[0], math.MaxInt32for i : 1; i < n; i {num : nums[i]if num > second {return true} else if num > first {second n…...

HarmonyOs编写一个案例实现一个照片选择(阶段进阶 四种需求 逐一完善)

需求1. .实现照片选择 并将选择好的照片展示出来 import { GoodItem } from ../06/modules;Entry Component struct PhotoPage {State message: string 实现一个相册;State List: GoodItem[] [{goods_name: dsfjlsjkfsf,goods_price: 100,goods_img: https://img1.baidu.com…...

洗衣机洗衣服一些知识

01智能:按衣物多少自动调节合适水位的标准洗涤程序 (需要30分钟时间) 02:大物:较大,较厚的衣服洗涤 03:轻柔:毛织品或内衣洗涤 04:快速:少量清污衣服洗涤 (13分钟) 05:浸泡:先浸泡一段时间再洗涤 06:单洗:只洗衣不脱水 07:单脱:只脱水不洗衣 08:洁桶:清洁洗衣桶 准备工作: (1)…...

探索文件系统:高效、可靠的文件管理与访问机制

文件系统的功能规划 内存就像是一个书包&#xff0c;容量有限&#xff0c;只能带着一部分东西。而图书馆则是一个专门存储和管理文件的地方&#xff0c;拥有更大的容量&#xff0c;并且可以永久保存文件。为了能够快速找到需要的文件&#xff0c;我们需要有一个书单来记录每本…...

启程与远征Ⅸ--优化生成式人工智能以满足业务需求的框架

生成类似人类的文本和语音曾经只存在于科幻小说中。但 GPT-3 和 PaLM 等大型语言模型 (LLM) 的快速发展让这一愿景更接近现实&#xff0c;解锁了从聊天机器人到内容创作等一系列有前景的商业应用。 然而&#xff0c;通用基础模型往往无法满足行业用例的需求。企业对其生成式 A…...

canal数据同步工具介绍与应用

canal服务 canal介绍canal版本与环境canal 服务集canal应用场景&#xff1a; canal常见问题xml配置问题连接认证问题jar版本问题连接问题 canal介绍 ‌1、Canal是‌阿里巴巴开源的‌MySQL增量数据订阅和消费工具&#xff0c;通过模拟MySQL的‌slave与‌master交互&#xff0c;捕…...

ubuntu18.04 设置静态地址

修改配置文件 sudo vim /etc/netplan/01-network-manager-all.yaml 代码如下&#xff1a; network: version: 2 renderer: NetworkManager ethernets: ens33: # 配置的网卡名称&#xff0c;可以使用ifconfig -a查看本机的网卡 dhcp4: no # 关闭动态IP设置 …...

jira敏捷开发管理工具视频教程Confluence工作流协同开发(2024)

正文&#xff1a; 随着Jira敏捷开发方法论的普及&#xff0c;Jira已经成为全球软件开发团队管理项目、任务和问题的首选工具。为了帮助团队更好地掌握Jira的核心功能&#xff0c;精心准备了一套全面开发技术及案例视频教程——《Jira敏捷开发管理工具视频教程Confluenc…...

【网络】TCP回显服务器和客户端的构造,以及相关bug解决方法

文章目录 ServerSocket构造方法方法 Socket构造方法方法 回显服务器&#xff08;Echo Server&#xff09;1. 构造方法2. 建立连接processConnection 方法的创建1. 读取请求并解析2. 根据请求计算响应3. 把响应写回给客户端 3. 完整代码 客户端&#xff08;Echo Client&#xff…...

Python知识点:如何使用Boto3进行AWS服务管理

使用 boto3 来管理 AWS 服务是一个非常强大的方式&#xff0c;因为 boto3 是 AWS 提供的官方 Python SDK。下面是使用 boto3 管理 AWS 服务的基本步骤&#xff0c;包括设置、操作和常见的 AWS 服务示例。 1. 安装 boto3 首先&#xff0c;确保你已经安装了 boto3。可以使用 pi…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

uni-app学习笔记三十五--扩展组件的安装和使用

由于内置组件不能满足日常开发需要&#xff0c;uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件&#xff0c;需要安装才能使用。 一、安装扩展插件 安装方法&#xff1a; 1.访问uniapp官方文档组件部分&#xff1a;组件使用的入门教程 | uni-app官网 点击左侧…...

HTTPS证书一年多少钱?

HTTPS证书作为保障网站数据传输安全的重要工具&#xff0c;成为众多网站运营者的必备选择。然而&#xff0c;面对市场上种类繁多的HTTPS证书&#xff0c;其一年费用究竟是多少&#xff0c;又受哪些因素影响呢&#xff1f; 首先&#xff0c;HTTPS证书通常在PinTrust这样的专业平…...