分页API异步循环嵌套请求实现问题及代码优化求助
修复并简化你的分页异步处理逻辑
先帮你拆解下当前代码的几个核心问题:
- 混用了回调式的
async.each和async/await,导致异步流程错乱,api.mockable的触发时机完全不对 - 循环范围写错了(
i < noPage会漏掉最后一页) async.each的迭代函数用了async,但手动调用cb()的方式根本没处理异步结果,导致api.mockable在图片请求还没完成时就被调用,自然items是空的- 第一页的处理其实重复了(你先获取第一页算总页数,循环里又重新获取一次)
下面是完全用原生async/await和Promise.all重构的简洁实现,逻辑更清晰,也解决了你的问题:
export const importData = async () => { const pageSize = 15; // 先拿第一页数据,计算总页数 const firstPage = await getItems(pageSize, 1); const totalPages = Math.ceil(firstPage.totalMerchandiseCount / pageSize); // 遍历每一页,从1到总页数(包含最后一页) for (let pageNum = 1; pageNum <= totalPages; pageNum++) { // 获取当前页的商品列表 const currentPage = await getItems(pageSize, pageNum); // 并行处理当前页所有商品的图片请求,效率更高 const processedItems = await Promise.all( currentPage.merchandiseList.map(async (item) => { try { const imageURL = await getImageURL(item.id, item.type); return { id: item.id, imageURL }; } catch (err) { console.error(`获取商品${item.id}图片失败:`, err); // 失败的条目可以选择返回null,之后过滤掉 return null; } }) ); // 过滤掉获取失败的条目 const validItems = processedItems.filter(Boolean); // 确保当前页所有图片都处理完,再调用同步API await api.mockable('sync', validItems); } console.log('所有页面处理同步完成!'); }; // 把getImageURL改成纯async/await风格,去掉嵌套的then/catch export const getImageURL = async (id, type) => { const url = `https://example.com/${id}`; const response = await axios.get(url); const $ = cheerio.load(response.data); // 这里替换成你实际提取图片URL的逻辑 const imageURL = $('img.product-img').attr('src'); // 示例 return imageURL; };
核心优化点:
- 用
Promise.all替代async.each,并行处理单页内的所有图片请求,既简化了代码,又提升了效率 - 修正了循环范围,确保所有页码(包括最后一页)都被处理
- 彻底抛弃回调式写法,全程用
async/await,异步流程一目了然 - 增加了单条图片请求的错误处理,不会因为一个商品的图片失败导致整页甚至整个流程中断
- 保证只有当前页所有图片都处理完成后,才调用
api.mockable,彻底解决items为空的问题
如果你需要所有页处理完再一次性同步数据:
如果你的需求是等所有页面的商品都处理完,再统一调用api.mockable,只需要稍微调整,把所有有效条目收集起来最后发送:
export const importData = async () => { const pageSize = 15; const firstPage = await getItems(pageSize, 1); const totalPages = Math.ceil(firstPage.totalMerchandiseCount / pageSize); const allProcessedItems = []; for (let pageNum = 1; pageNum <= totalPages; pageNum++) { const currentPage = await getItems(pageSize, pageNum); const processedItems = await Promise.all( currentPage.merchandiseList.map(async (item) => { try { const imageURL = await getImageURL(item.id, item.type); return { id: item.id, imageURL }; } catch (err) { console.error(`获取商品${item.id}图片失败:`, err); return null; } }) ); allProcessedItems.push(...processedItems.filter(Boolean)); } // 所有页面处理完成后,一次性同步所有数据 await api.mockable('sync', allProcessedItems); console.log('全部数据同步完成!'); };
这样就完全符合你说的“api.mockable需等待所有页处理完成才会调用”的需求,同时保证数据完整。
内容的提问来源于stack exchange,提问作者K20GH
相关产品推荐
相关产品推荐

