MST

星途 面试题库

面试题:如何在 Vuex 的 getters 中处理异步操作并实现缓存

假设你需要在 Vuex 的 getters 中获取一个异步接口的数据,并且希望对该数据进行缓存以避免重复请求。请描述实现这一功能的思路以及可能遇到的问题和解决方案。
19.1万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 初始化缓存:在 Vuex 的 state 中定义一个属性用于存储缓存的数据,同时定义一个属性标记数据是否已经缓存。
state: {
    asyncData: null,
    isDataCached: false
}
  1. 创建 getters:在 getters 中判断数据是否已经缓存。如果已缓存,直接返回缓存的数据;如果未缓存,则发起异步请求获取数据,并将数据缓存起来,同时更新缓存标记。
getters: {
    asyncDataGetter: (state, getters, rootState, rootGetters) => {
        if (state.isDataCached) {
            return state.asyncData;
        } else {
            // 这里假设使用 axios 进行异步请求
            import axios from 'axios';
            axios.get('/your-api-url')
               .then(response => {
                    state.asyncData = response.data;
                    state.isDataCached = true;
                    return state.asyncData;
                })
               .catch(error => {
                    console.error('Error fetching data:', error);
                });
        }
    }
}

可能遇到的问题及解决方案

  1. 首次加载延迟
    • 问题:首次加载时,由于需要等待异步请求完成,可能会导致数据显示延迟。
    • 解决方案:可以在组件中显示加载状态,例如使用一个 loading 标志,在数据未缓存且请求未完成时显示加载动画。同时,可以考虑使用服务端渲染(SSR)或静态站点生成(SSG),在构建或请求时就获取数据,减少客户端等待时间。
  2. 缓存更新问题
    • 问题:如果接口数据发生变化,缓存的数据不会自动更新,导致显示的数据与实际数据不一致。
    • 解决方案:提供手动更新缓存的方法,例如在组件中提供一个按钮,点击后调用 action 来清除缓存并重新获取数据。或者设置缓存的过期时间,当超过过期时间后,重新发起请求获取新数据。另外,可以通过订阅服务器推送(如 WebSocket)来实时更新缓存数据。
  3. 异步请求并发问题
    • 问题:如果在缓存未完成时多次访问 getters,可能会发起多个相同的异步请求。
    • 解决方案:可以使用一个标志来表示当前是否正在进行请求。在请求发起时设置标志为 true,请求完成后设置为 false。当再次访问 getters 且正在请求时,不再发起新的请求,而是等待当前请求完成并返回缓存数据。
state: {
    asyncData: null,
    isDataCached: false,
    isRequesting: false
},
getters: {
    asyncDataGetter: (state, getters, rootState, rootGetters) => {
        if (state.isDataCached) {
            return state.asyncData;
        } else if (state.isRequesting) {
            // 等待当前请求完成,这里可以返回一个 Promise 来处理
            return new Promise((resolve) => {
                const interval = setInterval(() => {
                    if (state.isDataCached) {
                        clearInterval(interval);
                        resolve(state.asyncData);
                    }
                }, 100);
            });
        } else {
            state.isRequesting = true;
            import axios from 'axios';
            axios.get('/your-api-url')
               .then(response => {
                    state.asyncData = response.data;
                    state.isDataCached = true;
                    state.isRequesting = false;
                    return state.asyncData;
                })
               .catch(error => {
                    console.error('Error fetching data:', error);
                    state.isRequesting = false;
                });
        }
    }
}