MST

星途 面试题库

面试题:Vue Pinia下如何优雅地处理多个相互依赖的异步数据流

在一个电商应用中,商品列表数据依赖于用户选择的分类,而每个商品的库存信息又需要在商品列表加载完成后单独请求。使用Pinia来管理这些数据流,描述你会如何设计状态和action来处理这种复杂的异步依赖关系,并且说明如何避免竞态条件。
26.3万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

1. 状态设计

  1. 商品分类状态
    const useStore = defineStore('main', {
        state: () => ({
            selectedCategory: null,
            // 可以根据实际情况,这里设置为分类的ID或者名称等
        }),
    });
    
  2. 商品列表状态
    const useStore = defineStore('main', {
        state: () => ({
            productList: [],
            isProductListLoading: false,
            productListError: null,
        }),
    });
    
  3. 商品库存状态
    const useStore = defineStore('main', {
        state: () => ({
            productInventories: {},
            // 以商品ID为键,库存信息为值的对象
            isInventoryLoading: {},
            // 以商品ID为键,是否正在加载库存的标志
            inventoryError: {},
            // 以商品ID为键,加载库存时的错误信息
        }),
    });
    

2. Action设计

  1. 加载商品列表
    const useStore = defineStore('main', {
        actions: {
            async loadProductList() {
                if (!this.selectedCategory) {
                    return;
                }
                this.isProductListLoading = true;
                this.productListError = null;
                try {
                    const response = await fetch(`/api/products?category=${this.selectedCategory}`);
                    if (!response.ok) {
                        throw new Error('Network response was not ok');
                    }
                    const data = await response.json();
                    this.productList = data;
                } catch (error) {
                    this.productListError = error;
                } finally {
                    this.isProductListLoading = false;
                }
            },
        },
    });
    
  2. 加载商品库存
    const useStore = defineStore('main', {
        actions: {
            async loadProductInventory(productId) {
                if (this.isInventoryLoading[productId]) {
                    return;
                }
                this.isInventoryLoading[productId] = true;
                this.inventoryError[productId] = null;
                try {
                    const response = await fetch(`/api/products/${productId}/inventory`);
                    if (!response.ok) {
                        throw new Error('Network response was not ok');
                    }
                    const data = await response.json();
                    this.productInventories[productId] = data;
                } catch (error) {
                    this.inventoryError[productId] = error;
                } finally {
                    this.isInventoryLoading[productId] = false;
                }
            },
        },
    });
    
  3. 组合操作
    const useStore = defineStore('main', {
        actions: {
            async loadProductData() {
                await this.loadProductList();
                this.productList.forEach((product) => {
                    this.loadProductInventory(product.id);
                });
            },
        },
    });
    

3. 避免竞态条件

  1. 加载商品列表时
    • 使用isProductListLoading标志,在加载过程中如果再次触发加载操作,直接返回,避免重复请求。例如,在loadProductList方法中,在开始加载前设置isProductListLoading = true,结束时设置为false。如果在加载过程中再次调用loadProductList,可以先检查isProductListLoading,如果为true,则不进行新的请求。
  2. 加载商品库存时
    • 对于每个商品的库存加载,使用isInventoryLoading[productId]标志。在loadProductInventory方法中,开始加载前检查if (this.isInventoryLoading[productId]) { return; },避免对同一商品库存的重复请求。同时,设置和清除这个标志来管理加载状态。
  3. 整体流程
    • 通过async/await确保loadProductList完成后再进行每个商品库存的加载,这样可以避免商品列表未加载完成就去请求库存的问题。在loadProductData方法中,await this.loadProductList();语句保证了商品列表加载完成后才开始加载商品库存。