解决请求过快导致loading闪烁问题

前言:当我们在写项目发起请求时,我们可能会习惯于在请求过程中数据还未返回时展示一个loading组件,请求结束后就隐藏loading,渲染数据。这是没有问题的,不过目前网速越来越快,请求都十分迅速,经常会导致loading组件刚呈现数据就已经返回了,导致loading组件闪烁,十分影响用户体验,但若是不用loading若部分用户网速不行,也会导致请求的长时间白屏问题,同样影响用户体验。所以就需要一个两全其美的方法。

1.Promise.all() 解决

我们可以利用定时器在固定时间后将一个promise状态改为成功,然后将这个promise与axios请求放入Promise.all()中,那么只有当两个promise都成功时才渲染数据,从而实现当请求过快时也能展示固定时间的loading效果。

const reolvePromise = (reolveTime: number): Promise<unknown> => { // 指定时间后返回状态成功的promise
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(`在${reolveTime}ms后返回成功Promise`)
    }, reolveTime)
  })
}

loading.value = true // 发送请求时开启
Promise.all([ajaxRequest(), reolvePromise(200)])
  .then((res) => { // Promise.all执行结果返回的数组顺序是按传入顺序决定的
    console.log(res[0])
  })
  .catch((err) => {
    console.log(err)
  })
  .finally(() => {
    loading.value = false
  })

虽然使用Promise.all()看起来很美好,但网速快请求迅速也要等待loading展示结束,这就有些强行展示loading的感觉了。

2.Promise.race() 解决

另外一种新方式是利用Promise.race()。同样利用定时器,在固定时间后将一个promise状态改为失败,然后将这个promise与axios请求放入Promise.race()中,这意味着在固定时间内请求返回就直接渲染数据,而超出固定时间才展示loading效果。

const rejectPromise = (rejectTime: number): Promise<unknown> => { // 指定时间后返回状态失败的promise
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error(`在${rejectTime}ms后返回失败Promise`))
    }, rejectTime)
  })
}

const request = ajaxRequest() // 记录请求的状态
Promise.race([request, rejectPromise(1000)])
  .then((res) => {
    // 成功意味着请求在固定时间内返回
  })
  .catch((err) => { // 超时,整体变成onrejected,展示loading并继续等待返回
    loading.value = true
    console.log(err.message)
    request
      .then((res) => {
        // 请求终于成功了,渲染数据
      })
      .finally(() => {
        loading.value = false
      })
  })

虽然使用Promise.race()看起来更美好了,但依然存在问题,如果规定1000ms是超时时间,若请求在1100ms时返回,则loading只会展示100ms,依然会出现闪烁现象,所以如果用此方法解决需要估算每个请求的平均花费时间,不要让超时时间十分靠近请求的平均花费时间。

3.Promise.all() 搭配 Promise.race() 终极解决方式

终极解决方式是将 Promise.all() 和 Promise.race() 搭配使用。先利用Promise.race()约束请求在超时时间内返回时就直接渲染,否则就固定展示一段时间的loading动画再渲染数据。即请求如果没有在 500ms 内返回则固定展示 1500ms 的loading,这样才十分完美。

function reqData (): void {
  const axiosRequest = ajaxRequest() // 记录请求的状态
  Promise.race([axiosRequest, rejectPromise(500)])
  .then((res) => {
    // 成功意味着请求在固定时间内返回
  })
  .catch((err) => { // 超时,整体变成onrejected,展示loading
    loading.value = true
    console.log(err.message)
    Promise.all([axiosRequest, reolvePromise(1500)])
      .then((res) => { // Promise.all执行结果返回的数组顺序是按传入顺序决定的
        console.log(res[0])
      })
      .catch((err) => {
        console.log(err)
      })
      .finally(() => {
        loading.value = false
      })
  })
}

好啦,到这里就说完啦,点个赞啊靓仔~

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值