MST

星途 面试题库

面试题:Vue中如何在组件生命周期内合理安排异步数据请求以避免数据加载问题

阐述在Vue组件的created、mounted等生命周期钩子函数中进行异步数据请求的优缺点,以及如何根据业务场景选择合适的生命周期钩子来发起请求,同时说明如何处理由于异步请求导致的数据加载不及时或多次请求的问题。
18.8万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

在created、mounted等生命周期钩子函数中进行异步数据请求的优缺点

  1. created钩子
    • 优点:在组件实例创建完成后立即执行,此时组件尚未挂载到DOM,适合一些不需要操作DOM的异步数据请求,能尽早开始获取数据,减少用户等待时间。
    • 缺点:如果请求的数据用于初始化DOM相关操作,可能因为DOM未挂载而导致问题。
  2. mounted钩子
    • 优点:组件挂载到DOM后执行,可安全地操作DOM,若数据用于渲染或操作DOM元素,在此处请求较为合适。
    • 缺点:相比created,开始请求数据时间稍晚,可能造成短暂的白屏或加载延迟。

根据业务场景选择合适的生命周期钩子来发起请求

  1. 数据用于初始化组件内部状态,不涉及DOM操作:优先选择created钩子,如获取用户基本信息用于组件内部逻辑判断。
  2. 数据用于渲染或操作DOM元素:使用mounted钩子,例如根据后台数据动态生成图表,需要操作DOM元素来绘制。

处理由于异步请求导致的数据加载不及时或多次请求的问题

  1. 数据加载不及时
    • 加载状态管理:在组件data中定义一个loading状态,在请求开始时设为true,请求结束设为false。在模板中根据loading状态显示加载动画。
    <template>
      <div>
        <div v-if="loading">Loading...</div>
        <div v-else>{{ data }}</div>
      </div>
    </template>
    <script>
    export default {
      data() {
        return {
          loading: false,
          data: null
        }
      },
      mounted() {
        this.loading = true;
        this.$axios.get('/api/data')
         .then(response => {
            this.data = response.data;
            this.loading = false;
          })
         .catch(error => {
            this.loading = false;
            console.error(error);
          });
      }
    }
    </script>
    
  2. 多次请求
    • 防抖与节流
      • 防抖:在短时间内多次触发请求时,防抖函数会在最后一次触发后等待一定时间再执行请求。例如搜索框输入联想功能,可使用防抖避免频繁请求。
      import { debounce } from 'lodash';
      
      export default {
        data() {
          return {
            searchText: ''
          }
        },
        methods: {
          search: debounce(function() {
            this.$axios.get('/api/search', { params: { q: this.searchText } })
             .then(response => {
                // 处理响应数据
              })
             .catch(error => {
                console.error(error);
              });
          }, 300)
        }
      }
      
      • 节流:规定在一定时间内只能触发一次请求,适用于用户频繁滚动页面加载更多数据场景。
      import { throttle } from 'lodash';
      
      export default {
        data() {
          return {
            page: 1,
            dataList: []
          }
        },
        methods: {
          loadMore: throttle(function() {
            this.$axios.get('/api/data', { params: { page: this.page } })
             .then(response => {
                this.dataList = [...this.dataList, ...response.data];
                this.page++;
              })
             .catch(error => {
                console.error(error);
              });
          }, 500)
        }
      }
      
    • 取消重复请求:在发送新请求前取消之前未完成的请求。例如在切换路由时,若上一个路由的请求还未完成,可取消该请求。
    import axios from 'axios';
    
    const CancelToken = axios.CancelToken;
    let cancel;
    
    export default {
      data() {
        return {
          data: null
        }
      },
      mounted() {
        this.$axios.get('/api/data', {
          cancelToken: new CancelToken(c => {
            cancel = c;
          })
        })
        .then(response => {
            this.data = response.data;
          })
        .catch(error => {
            if (axios.isCancel(error)) {
              console.log('Request canceled', error.message);
            } else {
              console.error(error);
            }
          });
      },
      beforeDestroy() {
        cancel && cancel();
      }
    }