随着Web应用程序越来越复杂,前端和后端之间的通信变得越来越重要。通常情况下,前端应用程序需要从后端API获取数据,以便在页面上呈现数据。但是,当后端API响应太快时,前端页面的loading动画可能会闪烁,这是因为API响应太快,loading动画不足以完全显示出来。
问题的原因
通常,loading动画是在前端应用程序中使用的,用于告知用户某些操作正在进行中。也就是下面这段代码:
loading = true;
ajax().finally(() => {
loading = false;
});
但在后端API响应过快的情况下,前端应用程序可能在loading动画完全显示之前就获取到了数据,从而导致loading动画闪烁或消失。
这种情况可能会让用户感到不安或者认为页面已经加载完毕,从而导致用户误解或者不满意。
解决方案
1.增加loading动画持续时间
一种解决方案是增加loading动画的持续时间。这样,即使后端API响应太快,loading动画仍有足够的时间显示出来。这可以通过增加loading动画的持续时间或者延迟获取数据的方式来实现。
但是,这种方法可能会使用户等待更长的时间,从而导致用户体验下降。因此,在决定使用此方法之前,需要仔细权衡其优缺点。
2.使用缓存机制
另一种解决方案是使用缓存机制。如果数据可以被缓存,则前端应用程序可以首先从缓存中获取数据,而不是直接从后端API获取数据。这样,即使后端API响应太快,loading动画仍有足够的时间显示出来。
在实现此方法时,需要考虑缓存的更新策略和缓存数据的有效期。否则,可能会导致用户看到旧的数据或者不一致的数据。
3.使用loading动画预加载
另一种解决方案是使用loading动画预加载。这意味着,在前端应用程序加载时,可以使用loading动画预加载数据。这样,即使后端API响应太快,前端应用程序也可以立即显示数据,而不需要等待loading动画的完成。
但是,这种方法也可能会增加前端应用程序的加载时间,从而和第一种方案一样导致用户等待时间更长。
不同场景代码
场景一:Promise.all
假设我有两个 ajax 请求时间分别是50ms
和150ms
,我现在希望不管是50ms
还是150ms
,loading 动画都有一个比较完整的展示时间。
这种情况只需要用一个延迟的 Promise.resolve(),通过 Promise.all 方法去拉长响应时间。
const delay = ms => new Promise((resolve, _) => setTimeout(resolve, ms));
loading = true;
Promise.all([ajaxPromise, delay(300)])
.then(handleSuccess)
.catch(handleError)
.finally(() => {
loading = false;
});
场景二:Promise.race
现在我希望响应时间超过100ms
的情况才展示 loading 动画。
这种情况只需要用一个延迟的 Promise.reject(),通过 Promise.race 方法去和 ajax 竞态。
const timeout = ms =>
new Promise((_, reject) => setTimeout(() => reject(Symbol.for('timeout')), ms));
Promise.race([ajaxPromise, timeout(100)])
.then(handleSuccess)
.catch(err => {
if (Symbol.for('timeout') === err) {
loading = true;
return ajaxPromise
.then(handleSuccess)
.catch(handleError)
.finally(() => {
loading = false;
});
}
return handleError(err);
});
但注意,当我的响应时间为101ms
的时候,闪烁还是无法避免的
场景三:Promise.all 和 Promise.race
现在我希望响应时间小于100ms
时不展示 loading 动画,大于100ms
时展示300ms
的 loading 动画时间。
const timeout = ms =>
new Promise((_, reject) => setTimeout(() => reject(Symbol.for('timeout')), ms));
const delay = ms => new Promise((resolve, _) => setTimeout(resolve, ms));
const request = ({ config, target, timeoutTime = 100, delayTime = 300 }) => {
// 返回promise的ajax请求
const promise = axios(config);
const startLoading = target => {
if (!target) {
return;
}
// startLoading
};
const endLoading = () => {
// endLoading
};
const handleSuccess = data => {
// 兼容Promise.all和Promise.race不同的返回值
const response = Array.isArray(data) ? data[0] : data;
// 处理成功的情况
return Promise.resolve(response.data);
};
const handleError = ({ response }) => {
// 处理失败的情况
return Promise.reject(response);
};
return Promise.race([promise, timeout(timeoutTime)])
.then(handleSuccess)
.catch(err => {
if (Symbol.for('timeout') === err) {
startLoading(target);
return Promise.all([promise, delay(delayTime)])
.then(handleSuccess)
.catch(handleError)
.finally(() => {
endLoading();
});
}
return handleError(err);
});
};
timeoutTime
和 delayTime
可以根据自己的网站调整,推荐使用此场景。
如果你有更好的方案,欢迎评论👏
站点介绍:记录所学知识,缩短和大神的差距!
站点图标:https://res.liuyuyang.net/usr/images/avatar.jpg
站点地址:https://liuyuyang.net/
描 述:什么都懂一点点皮毛
链 接:https://blog.qsuu.cn
头 像:https://cdn.qsuu.cn/2024/02/25/65daa884f34be.jpg
已添加贵站信息