如何使用 promise all 处理大量请求

How to process large number of requests with promise all

我有大约 5000 个链接,我需要抓取所有这些链接。所以我想知道是否有比这更好的方法。这是我的代码。

let urls = [ 5000 urls go here ];

const doms = await getDoms(urls);

// processing and storing the doms

getDoms = (urls) => {

  let data = await Promise.all(urls.map(url => {
    return getSiteCrawlPromise(url)
  }));
  return data;

}

getSiteCrawlPromise = (url) => {

  return new Promise((resolve, reject) => {
    let j = request.jar();
    request.get({url: url, jar: j}, function(err, response, body) {
        if(err)
          return resolve({ body: null, jar: j, error: err});
        return resolve({body: body, jar: j, error: null});
    });
  })

} 

Promise 中是否实现了一种机制,可以将作业分配给多个线程和进程。那么 return 整个输出? 而且我不想将 url 分成更小的片段并处理这些片段

Javascript 并没有内置这样的机制,至少现在是这样。

您可以使用提供更多功能的第三方 Promise 库,例如 Bluebird,您可以在其中使用它们的并发功能:

const Promise = require('bluebird');

// Crawl all URLs, with 10 concurrent "threads".
Promise.map(arrayOfUrls, url => {
    return /* promise for crawling the url */;
}, { concurrency: 10 });

另一种选择是使用专用的节流库(我强烈推荐 bottleneck),它可以让您表达任何通用类型的速率限制。这种情况下的语法将类似于您已有的语法:

const Bottleneck = require('bottleneck');
const limit = new Bottleneck({ maxConcurrent: 10 });

const getCallSitePromise = limit.wrap(url => {
    // the body of your getCallSitePromise function, as normal
});

// getDoms stays exactly the same

可以自己解决这个问题,但带上一个(或两个!)上述库将为您节省大量代码。

The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.

Promises to "divide jobs into multiple threads and process" 中没有内置机制。如果必须这样做,则必须将 urls 数组分割成更小的数组,并将分割的数组同时排队到单独的爬虫实例中。

但是,完全没有必要那样做,因为你使用的是 node-js 和 node-crawler,你可以使用 node-crawler 的 maxConnections 选项。 这就是它的目的,最终结果也是一样的。您将在多个线程上抓取 url,而不会在手动分块和处理多个抓取工具实例上浪费时间和精力,也不会依赖于任何并发库。