嵌套异步请求最佳实践:Next.js购物车数据获取代码优化问询
购物车数据获取代码优化建议请求
我正在用Axios调用第三方API获取用户购物车数据,接口返回产品ID列表和对应数量,之后我会遍历这些ID获取完整产品信息。目前代码能正常运行,但我对Promise不太熟悉,想请教代码优化方向:是否应该拆分第二个then?当前写法是否符合最佳实践?补充:我用的是Next.js,这个函数会在getStaticProps里调用。
export const getCartProducts = async () => { const data = await axios // get most recent cart of user .get('https://example.com/api/carts', { params: { display: 'full', output_format: 'JSON', 'filter[id_customer]': '[0]', sort: '[id_DESC]', limit: '1', }, headers: { Authorization: 'Basic ' + btoa(process.env.API_AUTH + ':'), Accept: 'application/json', }, }) .then((cartResponse) => { const cart = cartResponse.data.carts[0]; // return product ids and quantity const cartMeta: TCartItem[] = cart.associations.cart_rows.map( (item: any) => { const { id_product, quantity } = item; return { id: id_product.toString(), quantity, }; } ); return cartMeta; }) .then(async (cartMeta: TCartItem[]) => { const items: (TCartProduct | undefined)[] | void = await axios // fetch product data for each id .all(cartMeta.map((item: TCartItem) => getProductById(item.id))) .then((products) => products.map((product: TProduct | null) => { if (product) { const productCartMeta = cartMeta.find( (meta) => meta.id === product?.id ) as TCartItem; // return data needed for product display on cart page return { ...product, quantity: productCartMeta?.quantity ?? 0, }; } return; }) ) .catch((error) => handleError(error)); return items; }) .catch((error) => handleError(error)); // called in Next.js `getStaticProps` so needs to default to null return data ?? null; };
优化建议:统一用async/await替代混合写法
你的代码同时混用了await和Promise链式then,在async函数里更推荐统一使用async/await,这种写法比链式then更易读,也更容易拆分逻辑,符合现代JS最佳实践。
1. 拆分第二个then是合理的,甚至可以拆得更细
把每个独立逻辑拆成线性步骤,或者抽成小函数,让代码职责更单一,调试和维护起来更方便。比如可以拆成这几步:
- 获取购物车基础数据
- 提取产品ID与数量的映射关系
- 批量获取所有产品详情
- 合并产品详情和数量信息
2. 优化后的代码示例
export const getCartProducts = async () => { try { // 1. 获取用户最新购物车数据 const cartResponse = await axios.get('https://example.com/api/carts', { params: { display: 'full', output_format: 'JSON', 'filter[id_customer]': '[0]', sort: '[id_DESC]', limit: '1', }, headers: { Authorization: 'Basic ' + btoa(process.env.API_AUTH + ':'), Accept: 'application/json', }, }); const cart = cartResponse.data.carts[0]; // 处理空购物车或无产品的边界情况 if (!cart?.associations?.cart_rows?.length) { return null; } // 2. 用对象映射存储ID与数量,替代数组find(性能从O(n)优化到O(1)) const cartQuantityMap = cart.associations.cart_rows.reduce((map, item) => { const productId = item.id_product.toString(); map[productId] = item.quantity; return map; }, {} as Record<string, number>); // 3. 批量获取所有产品详情 const productIds = Object.keys(cartQuantityMap); const products = await axios.all(productIds.map(id => getProductById(id))); // 4. 合并产品信息与数量,过滤无效产品 const items = products .filter(product => product !== null) .map(product => ({ ...product, quantity: cartQuantityMap[product.id] ?? 0, })); return items; } catch (error) { handleError(error); // 符合getStaticProps要求,出错时返回null return null; } };
关键优化点说明
- 统一async/await风格:避免回调嵌套,代码线性化,可读性大幅提升
- 性能优化:用对象映射替代数组
find,批量处理产品时匹配效率更高 - 边界处理:提前判断空购物车情况,避免后续逻辑报错
- 集中错误处理:所有逻辑放在一个
try/catch中,无需多个catch分支,更简洁 - 过滤无效数据:直接剔除
getProductById返回的null值,避免数组中出现undefined
关于是否拆分第二个then的结论
当前的链式then写法虽然能运行,但在async函数里拆分并改用await是更优的选择。拆分后每个步骤职责单一,代码结构更清晰,也更贴合Next.js中getStaticProps常用的线性await代码风格,后续维护和调试都会更轻松。
内容的提问来源于stack exchange,提问作者lizzmo
相关产品推荐
相关产品推荐

