记录--Loading 用户体验 - 加载时避免闪烁
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
在切换详情页中有这么一个场景,点击上一条,会显示上一条的详情页,同理,点击下一条,会显示下一条的详情页。

伪代码如下所示:
我们定义了一个 switcher 模版, 用户点击上一条、下一条时调用 goToPreOrNext 方法。该页面通过 loadingDone 状态判断是否展示加载效果。
// html
<thy-loading [thyDone]="loadingDone"></thy-loading>
<ng-container *ngIf="loadingDone">
<styx-pivot-detail>
...
<thy-arrow-switcher
...
(thyPrevious)="goToPreOrNext($event)"
(thyNext)="goToPreOrNext($event)"
></thy-arrow-switcher>
...
</styx-pivot-detail>
</ng-container>
在 goToPreOrNext 方法中,当调用该方法时,通过 goToPreOrNextResolve 接口返回下一条的详情 id,通过该 id 请求详情数据。
// 请求下一条 id
fetchPreOrNext(event: ThyArrowSwitcherEvent) {
...
this.goToPreOrNextResolve(event.index, topicId).subscribe(
(id: string) => {
this.getDetail(id);
}
...
)
} // 请求详情数据
getDetail(postId: string) {
this.loadingDone = false;
this.store
.fetchPost(postId)
.pipe(
finalize(() => {
this.loadingDone = true;
})
)
.subscribe();
}
这看起来好像没有什么问题,应该一般都是这么干的,我们运行看看。

如何切换时候不闪?
与最上面的相比,有没有发现每次切换时,都会闪一下,用户体验很不好,有没有办法可以解决它?
这个问题就是 loadingDone 的状态切换导致的,我们把 loadingDone 干掉是不是就可以了?
如下代码所示:
// 请求详情数据
getDetail(postId: string) {
// 注释掉这一行
// this.loadingDone = false;
this.store
.fetchPost(postId)
.pipe(
finalize(() => {
this.loadingDone = true;
})
)
.subscribe();
}

好像方案可行?
但是把网络调成低速 3G 后,会发现,我们的加载效果没了,页面像卡住了一样,这当然不行。

有没有更好的方案?
setTimeout 方案
把先前 loadingDone 状态不放到 getDetail 方法中,而是单独拿出来紧跟 this.getDetail(id) 后面。
代码如下:
// 定义一个 timer
**private timer = null;** // 请求下一条 id
fetchPreOrNext(event: ThyArrowSwitcherEvent) {
...
this.goToPreOrNextResolve(event.index, topicId).subscribe(
(id: string) => {
this.getDetail(id); **this.timer = setTimeout(() => {
this.loadingDone = false;
}, 500);** }
...
)
} // 请求详情数据
getDetail(postId: string) {
// 删除掉该行loadingDone 代码
**// this.loadingDone = false;**
this.store
.fetchPost(postId)
.pipe(
finalize(() => {
this.loadingDone = true;
// 记得清除
**clearTimeout(this.timer);**
})
)
.subscribe();
}
这么做的含义就是,我们给到 loadingDone 500ms 的缓冲时间,如果 500ms 内返回数据了,则没有 loading 的效果,如果没有加载回来,在会显示加载中。
一般情况如下所示:

低速网络下的效果:

这确实是一种方案,但是总感觉哪里怪怪的。
这里是个定时任务并且 500ms 后触发。试想一种结果,当我快速点击下一条并且在 300ms 获取到了数据并把 loadingDone 状态置为 true, 但 500ms时,loadingDone 状态置为 false,造成假死的情况,显然这不是我们想要的。
那这该如何解决?
RxJS 大法
抛去使用 setTimeout 的方案,我们对 getDetail 代码改成如下的形式。
大致的思路是,将请求的 loading 状态与数据获取的状态分离,并定义了两个流 result$ 和 showLoadingIndicator$。
result$ 流请求到数据之后,之后之后的一些操作, showLoadingIndicator$ 流则负责 loading 状态的推送。
来看看怎么一步一步实现的:
首先我们定义一个请求的流。
const fetchPost$ = () => this.store.fetchPost(postId);
然后分别定义了两个流 result$ 和 showLoadingIndicator$。这里的 share() 函数是因为会有两个订阅它的地方。
const result$ = fetchPost$().pipe(share()); const showLoadingIndicator$;
然后我们来处理 showLoadingIndicator$ 流。
我们期望在 500ms 内请求到的数据,则不应该展示 loading,否则,应该展示 loading 状态。
const showLoadingIndicator$ = timer(500).pipe(mapTo(true), takeUntil(result$))
如果在 500ms 后很快请求到了数据,为了避免闪屏,我们需要让 loading 至少显示 1s。然后使用 merge() 合并这两种结果。
const showLoadingIndicator$ = merge(
timer(500).pipe(mapTo(true), takeUntil(result$)),
combineLatest(result$, timer(1000)).pipe(mapTo(false))
).pipe(startWith(false), distinctUntilChanged());
最后订阅它们。
result$.subscribe(
result => {
// 请求到结果后的操作
},
error => {
// TODO
}
); showLoadingIndicator$.subscribe(isLoading => {
// 更新 loadingDone 状态
this.loadingDone = !isLoading;
});
完整的代码如下:
// 请求下一条 id
fetchPreOrNext(event: ThyArrowSwitcherEvent) {
...
this.goToPreOrNextResolve(event.index, topicId).subscribe(
(id: string) => {
this.getDetail(id);
}
...
)
} // 请求详情数据
getDetail(postId: string) { const fetchPost$ = () => this.store.fetchPost(postId); const result$ = fetchPost$().pipe(share()); const showLoadingIndicator$ = merge(
timer(500).pipe(mapTo(true), takeUntil(result$)),
combineLatest(result$, timer(1000)).pipe(mapTo(false))
).pipe(startWith(false), distinctUntilChanged()); result$.subscribe(
result => {
// TODO
},
error => {
// TODO
}
); showLoadingIndicator$.subscribe(isLoading => {
this.loadingDone = !isLoading;
});
}
如果想更细致知道如何实现的,参考下面这篇文档:
Loading indication with a delay and anti-flickering in RxJS

本文转载于:
https://juejin.cn/post/7176943529057321017
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

记录--Loading 用户体验 - 加载时避免闪烁的更多相关文章
- WinForm用户自定义控件,在主窗体加载时出现闪烁;调用用户控件出现闪烁,需要鼠标才能够显示
转载自:http://www.dotblogs.com.tw/rainmaker/archive/2012/02/22/69811.aspx 解决方案: 在调用用户控件的窗体里面添加一下代码: pro ...
- cocos2d-html5如何更改预加载时的默认的logo图片和删除loading小圈圈
找到框架目录(2.1.4)里的cocos2d目录里有个CCLoader.js文件,找到LoaderScene的构造方法ctor,可以看到有一行: this._logoTexture.src= &quo ...
- WebApi 数据保护操作未成功。这可能是由于未为当前线程的用户上下文加载用户配置文件导致的。当线程执行模拟时,可能会出现此情况。","ExceptionType":"System.Security.Cryptography.CryptographicException","StackTrace
在调用System.Security.Cryptography.ProtectedData.Protect方法来保护私密信息时,IIS可能会报以下错误:CryptographicException: ...
- 页面数据加载完成时,显示loading页面.数据加载完,loading隐藏.
一,引入三个文件 jQuery版本使用 jQuery v1.7.1 jquery-easyui文件中,引入easyui-lang-zh_CN.js的js 做数据加载时使用jquery.blockui. ...
- 寻找丢失的微服务-HAProxy热加载问题的发现与分析 原创: 单既喜 一点大数据技术团队 4月8日 在一点资讯的容器计算平台中,我们通过HAProxy进行Marathon服务发现。本文记录HAProxy服务热加载后某微服务50%概率失效的问题。设计3组对比实验,验证了陈旧配置的HAProxy在Reload时没有退出进而导致微服务丢失,并给出了解决方案. Keywords:HAProxy热加
寻找丢失的微服务-HAProxy热加载问题的发现与分析 原创: 单既喜 一点大数据技术团队 4月8日 在一点资讯的容器计算平台中,我们通过HAProxy进行Marathon服务发现.本文记录HAPro ...
- 页面加载时loading效果
页面加载时loading效果: <!DOCTYPE html> <html lang="en"> <head> <meta charset ...
- ionic js 加载动画 ionSpinner 提供了许多种旋转加载的动画图标。当你的界面加载时,你就可以呈现给用户相应的加载图标。 该图标采用的是SVG
ionic 加载动画 ion-spinner ionSpinner 提供了许多种旋转加载的动画图标.当你的界面加载时,你就可以呈现给用户相应的加载图标. 该图标采用的是SVG. 用法 <ion- ...
- JqueryEasyUI 解决IE下加载时页面错乱的问题 分类: JavaScript JqueryEasyUI 2014-09-20 09:50 545人阅读 评论(1) 收藏
问题描述: 一直觉得jqueryeasyui在IE下的渲染效果不大好,尤其刚进入页面时的加载,页面会出现布局错乱,虽然是一闪而过,但是给用户的体验不好: 可以通过在页面onload时,增加一个遮罩层, ...
- jquery mobile 的loading提示“正在加载...”在不同版本中的不同实现方式
在jquery mobile开发中,在页面的切换.或者ajax获取数据时由于网速慢等其他原因,会有一个加载的时间,如果能在这段时间给一个“正在加载...”的提示,用户体验会更好.下面来简单的介绍一下在 ...
- 你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)
前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程, ...
随机推荐
- Asp-Net-Core学习笔记:3.使用SignalR实时通信框架开发聊天室
SignalR牛刀小试 在MVP杨老师的博客里看到这么个东西,我还以为是NetCore3才推出的新玩意,原来是已经有很多年的历史了,那看来还是比较成熟的一个技术了. 简介 SignalR是一个.NET ...
- 【架构师视角系列】QConfig配置中心系列之架构设计(一)
目录 声明 配置中心系列文章 一.架构 基础模型 架构图 架构分层 运行规则 模块划分 Admin模块 Client模块 Server模块 二.总结 三.最后 声明 原创文章,转载请标注.https: ...
- 机器学习基础01DAY
数据的特征抽取 现实世界中多数特征都不是连续变量,比如分类.文字.图像等,为了对非连续变量做特征表述,需要对这些特征做数学化表述,因此就用到了特征提取. sklearn.feature_extract ...
- Java操作EasyExcel实现导入导出入门
介绍 EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单.节省内存著称.EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从 ...
- Direct2D 另一种与D3D创建类似的方法
在进行D2D学习的时候,发现了这样一篇文档, Direct2D Quickstart for Windows 8 只有这么一小段介绍, Direct2D is a native-code, immed ...
- win32 - 使用LookupAccountName查找SID
可以使用LookupAccountNameA获取sid. LookupAccountName函数接受系统名称和帐户作为输入.它检索该帐户的安全标识符(SID)以及在其上找到该帐户的域的名称. 使用此a ...
- leetcode 将有序数组转换为二叉搜索树
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树. 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树. 示例 ...
- 【LeetCode二叉树#06】获取二叉树的所有路径(分析递归中的回溯机制)
二叉树所有路径 力扣题目链接(opens new window) 给定一个二叉树,返回所有从根节点到叶子节点的路径. 说明: 叶子节点是指没有子节点的节点. 示例: 思路 根据题意,每次遍历至子节点, ...
- 用Docker发布网站时,自动下载Directory.Build.props及其Import的文件
为Blazor网站项目,"添加Docker支持" 这时,网站项目根目录下会新增Dockerfile. 里面文字内容如下 #See https://aka.ms/customizec ...
- 在Ubuntu搭建DHCP服务器
一.提供DHCP的服务器,自己必须有固定的IP地址 不然局域网就乱了,服务器自身启动(比如搭建完DHCP服务后,重新启动了服务器)的时候,DHCP服务器没有IP地址,无法和自己的DHCP服务通信. 在 ...
