What I do:

我爬网,我这样做的方式是,我有一个网站链接列表,并从每个创建一个promise (promise 基本上是一个爬虫).我这样做的顺序,例如,如果我有10个链接,我会爬第一个链接,等待它完成,爬第二个链接,等等.

What I need:

我想要实现的是将我的promise 组合在一起.每个组将并行运行,但组列表将按顺序运行.

例如,我有10个链接,我将从它们中创建10个promise . 在那之后,我会把promise 分成小组,每组最多3个promise . 之后应该先爬行3(因为他们是第一组),等待他们完成,然后运行第4,5,6,因为他们是第二组,等等.

What I tried:

我创造了一种拆分promise 的方法:

export function splitPromises<T>(promises: Promise<T>[], maxPerItem: number): Promise<T>[][] {
  const splitPromisesList: Promise<T>[][] = [];
  let currentSplit: Promise<T>[] = [];

  for (let i = 0; i < promises.length; i++) {
    currentSplit.push(promises[i]);

    if (currentSplit.length === maxPerItem || i === promises.length - 1) {
      splitPromisesList.push(currentSplit);
      currentSplit = [];
    }
  }

  return splitPromisesList;
}

在使用拆分和调用promise 的方法之后:

async function crawler(links: string[], page: Page): Promise<MyData[]> {
  const list: MyData[] = [];

  const crawlPromises = links.map(async (link, index) => {
    try {
      const newPage = await page.browser().newPage();
      const detail = await crawlLink(link, newPage);
      await newPage.close();
      return detail;
    } catch (e) {
      console.log(e);
      return null as MyData;
    }
  });

  const groupedPromises = splitPromises<MyData>(crawlPromises, 3);
  let results: MyData[] = [];

  for (const group of groupedPromises) {
    results = await Promise.all(group);
    const filteredResults: MyData[] = results.filter((detail) => detail !== null) as MyData[];
    list.push(...filteredResults);
  }


  return list;
}

What are my issues:个 我不确定我做错了什么,但它一次执行所有promise ,而不是按组执行.

推荐答案

一旦创建了promise ,工作就已经在进行中了.分批兑现promise 不会耽误工作.相反,你需要批量处理creation个promise .

将数组分成块的函数仍然有用,但您需要让它在字符串数组上工作,而不仅仅是在promise 数组上工作:

export function splitArray<T>(array: T[], maxPerItem: number): T[][] {
  const splitList: T[][] = [];
  // ... basically the same implementation as before, with different variable names
  return splitList;
}

然后你需要把这links个数据块分成一个块,并从这一个块中创建你的promisearray.然后,您将等待该块完成,然后再继续下一个块.

async function crawler(links: string[], page: Page): Promise<MyData[]> {
  const list: MyData[] = [];

  const chunks = splitArray(links, 3);

  for (const chunk of chunks) {
    const crawlPromises = chunk.map(async (link, index) => {
      // .. same as before, except we're mapping over `chunk` instead of `links`
    });
    const results = await Promise.all(crawlPromises);
    const filteredResults: MyData[] = results.filter((detail) => detail !== null) as MyData[];
    list.push(...filteredResults);
  }

  return list;
}

Javascript相关问答推荐

如何在使用fast-xml-parser构建ML时包括属性值?

从实时数据库(Firebase)上的子类别读取数据

在观察框架中搜索CSV数据

如何避免页面第一次加载时由于CSS样式通过JavaScript更改而出现闪烁

Reaction Native中的范围滑块

如何将多维数组插入到另一个多维数组中?

使用VUE和SCSS的数字滚动动画(&;内容生成)

TypeError:无法读取未定义的属性(正在读取';宽度';)

在FAQ Accodion应用程序中使用React useState时出现问题

是否可以将Select()和Sample()与Mongoose结合使用?

如何使本地html页面在重新加载时保持当前可隐藏部分的打开状态?

不同表的条件API端点Reaction-redux

Socket.IO在刷新页面时执行函数两次

FireBase FiRestore安全规则-嵌套对象的MapDiff

与在编剧中具有动态价值的定位器交互

AG-GRIDreact 显示布尔值而不是复选框

使用props 将VUE 3组件导入JS文件

如何将值从后端传递到前端

如何使用Angular JS双击按钮

我如何让我的弹力球在JavaScript和HTML画布中相互碰撞后改变 colored颜色 ?