首页 前端知识 解决请求过快导致loading闪烁问题

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

2024-09-08 02:09:16 前端知识 前端哥 488 976 我要收藏

前言:当我们在写项目发起请求时,我们可能会习惯于在请求过程中数据还未返回时展示一个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
      })
  })
}

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

转载请注明出处或者链接地址:https://www.qianduange.cn//article/17867.html
标签
评论
发布的文章

数据持久化(Json)

2024-09-28 23:09:01

JSON Gate 开源项目教程

2024-09-28 23:09:00

【C 】Ubuntu安装jsoncpp

2024-09-28 23:09:58

http请求json

2024-09-28 23:09:58

JSON 格式详解

2024-09-28 23:09:53

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!