You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

分页API异步循环嵌套请求实现问题及代码优化求助

修复并简化你的分页异步处理逻辑

先帮你拆解下当前代码的几个核心问题:

  1. 混用了回调式的async.each和async/await,导致异步流程错乱,api.mockable的触发时机完全不对
  2. 循环范围写错了(i < noPage会漏掉最后一页)
  3. async.each的迭代函数用了async,但手动调用cb()的方式根本没处理异步结果,导致api.mockable在图片请求还没完成时就被调用,自然items是空的
  4. 第一页的处理其实重复了(你先获取第一页算总页数,循环里又重新获取一次)

下面是完全用原生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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 06:27:55