我需要下载大约5万个网页,从中获取一些数据并将其放入变量。
我把每个请求都包装成承诺,然后Promise.all()它们。我使用Request库。
简化代码:

const request = require('request');
const urls = [url1, url2, ...];
const promises = [];

urls.forEach(url => {
    promises.push((resolve, reject) => {
        request(url, (error, response, body) => {
            if(error){ reject(error); return; }

            // do something with page

            resolve(someData);
        });
    });
});

Promise.all(promises.map(pr => new Promise(pr)))
    .then((someDataArray)=>{ /* process data /* });

但我收到ENFILE异常,它表示系统中打开的文件太多(在我的桌面上,打开的文件的最大数量是2048个)。
我知道承诺是靠创造来实现的,但我不能解决这个问题。
也许还有别的办法?
谢谢你的回复。

最佳答案

您需要的是启动n个请求,然后在一个请求完成时启动一个新的请求(无论是否成功)。
有很多这样的库,但是能够自己实现这种限制是很重要的:

const request = require('request');
const urls = [url1, url2, ...];
const MAX_QUERIES = 10;
var remaining = urls.length;

const promises = [];

function startQuery(url){
    if (!url) return;
    request(url, (error, response, body) => {
        if (error) // handle error
        else // handle result
        startQuery(urls.shift());
        if (--remaining==0) return allFinished();
    });
}

for (var i=0; i<MAX_QUERIES; i++) startQuery(urls.shift());

function allFinished(){
    // all done
}

08-28 06:31