MST

星途 面试题库

面试题:Vue生命周期钩子结合异步数据加载时的性能优化

假设你在一个大型Vue项目中,多个组件都需要在生命周期钩子中进行异步数据加载。随着项目规模的扩大,出现了性能问题。请阐述你会采取哪些策略来优化异步数据加载性能,比如如何避免重复请求、如何处理并发请求等,并结合Vue的生命周期钩子函数详细说明实现思路。
25.7万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

避免重复请求

  1. 使用缓存
    • 思路:在Vue组件外创建一个缓存对象,用于存储已经请求过的数据。在组件的createdbeforeMount钩子中,在发起请求前先检查缓存。如果缓存中已有对应数据,则直接使用缓存数据,避免重复请求。
    • 示例代码
    const dataCache = {};
    export default {
      data() {
        return {
          dataFromApi: null
        };
      },
      created() {
        const cacheKey = 'your - api - key';
        if (dataCache[cacheKey]) {
          this.dataFromApi = dataCache[cacheKey];
        } else {
          // 发起异步请求
          this.$axios.get('/your - api - url')
         .then(response => {
            this.dataFromApi = response.data;
            dataCache[cacheKey] = response.data;
          });
        }
      }
    };
    
  2. 共享数据组件
    • 思路:将数据请求逻辑封装到一个共享组件中,其他需要该数据的组件通过props或Vuex等状态管理工具获取数据。这样可以保证数据只请求一次,多个组件复用该数据。
    • 示例代码(使用Vuex)
    • Vuex store.js
    import Vue from 'vue';
    import Vuex from 'vuex';
    import axios from 'axios';
    
    Vue.use(Vuex);
    
    const state = {
      sharedData: null
    };
    
    const mutations = {
      SET_SHARED_DATA(state, data) {
        state.sharedData = data;
      }
    };
    
    const actions = {
      async fetchSharedData({ commit }) {
        const response = await axios.get('/your - api - url');
        commit('SET_SHARED_DATA', response.data);
        return response.data;
      }
    };
    
    export default new Vuex.Store({
      state,
      mutations,
      actions
    });
    
    • 组件中使用
    <template>
      <div>
        {{ sharedData }}
      </div>
    </template>
    
    <script>
    export default {
      computed: {
        sharedData() {
          return this.$store.state.sharedData;
        }
      },
      created() {
        if (!this.sharedData) {
          this.$store.dispatch('fetchSharedData');
        }
      }
    };
    </script>
    

处理并发请求

  1. 使用Promise.all
    • 思路:当多个组件需要同时发起异步请求时,可以将这些请求的Promise对象收集到一个数组中,然后使用Promise.all方法。Promise.all会等待所有Promise都完成(或其中一个失败),这样可以避免不必要的竞争和重复请求,并且能更高效地管理多个并发请求。
    • 示例代码
    export default {
      data() {
        return {
          data1: null,
          data2: null
        };
      },
      created() {
        const promise1 = this.$axios.get('/api/data1');
        const promise2 = this.$axios.get('/api/data2');
    
        Promise.all([promise1, promise2])
       .then(([response1, response2]) => {
          this.data1 = response1.data;
          this.data2 = response2.data;
        });
      }
    };
    
  2. 限制并发数
    • 思路:如果并发请求过多可能会导致性能问题,可以通过控制并发请求的数量来优化。可以使用队列的方式,将请求依次放入队列,按照一定的并发数依次执行请求。
    • 示例代码(使用简单队列和定时器模拟)
    const requestQueue = [];
    const maxConcurrent = 2;
    let currentCount = 0;
    
    function enqueueRequest(request) {
      requestQueue.push(request);
      processQueue();
    }
    
    function processQueue() {
      while (currentCount < maxConcurrent && requestQueue.length > 0) {
        const request = requestQueue.shift();
        currentCount++;
        request()
       .then(() => {
          currentCount--;
          processQueue();
        });
      }
    }
    
    export default {
      data() {
        return {
          data1: null,
          data2: null
        };
      },
      created() {
        enqueueRequest(() => this.$axios.get('/api/data1')
       .then(response => {
          this.data1 = response.data;
        }));
        enqueueRequest(() => this.$axios.get('/api/data2')
       .then(response => {
          this.data2 = response.data;
        }));
      }
    };
    

在Vue生命周期钩子函数中,created钩子通常是发起异步数据请求的最佳时机,因为此时组件实例已经创建,数据观测和事件机制都已就绪,但DOM还未挂载,所以不会阻塞DOM渲染。beforeMount钩子也可以用于发起请求,但相比之下,created钩子更靠前,能更早地开始数据加载,减少用户等待时间。如果数据请求依赖于DOM元素(虽然不常见),可以在mounted钩子中发起请求,但要注意避免阻塞页面渲染。