如何管理多个承诺

How to manage multiple promises

我正在使用 node.js 编写爬虫程序。首先,我需要获取主页以获取该页面上每个项目的URL,然后我爬取每个项目的URL以逐一获取它们的详细信息

fetchPage(url)是得到HTML一个link

的文本
function fetchPage(url){
    return new Promise(
        (resolve,reject)=>{
            agent
            .get(url)
            .end(function(err,res){
                if (err){
                    reject(err);
                } else{
                    resolve(res.text);
                }
            });
        });
}

这是本爬虫的全局调用

fetchPage(link).then(
    (result)=>{
        const urls=getUrls(result);
        for (var i=0;i<5;i++){
            fetchItem(urls[i].link).then(
                (result)=>{
                    console.log('Done');
                },
                (error)=>console.log(error)
            );
        }
    },
    (error)=>console.log(error)
);

我在获取主页后处理了所有项目的 URLs(通过 getUrls

fetchItem(url) 是另一个 Promise,它确保项目的每个 HTML 文本在被 fetchPage[=21 获取后应通过 getItem 处理=]

function fetchItem(url){
    return new Promise(
        (resolve,reject)=>{
            fetchPage(url).then(
                (result)=>{
                    getItem(result);
                },
                (error)=>reject(error)
            );
        });
}

它确实会爬行。它确实得到了我需要的所有物品,而且没有任何信息缺失。

但是我的代码有问题。为什么控制台不为我记录 Done 消息?

结果顺序不正确。爬取结果的顺序和我预想的不一样,和网站上的顺序不一样

请指出我对这些异步控制的误解和错误之处?如何保证它们的顺序?如何修复此代码以满足?

如果我想在完全抓取所有项目后记录一条消息 All done,我应该怎么做,以确保它们以正确的顺序完全提取?

Done 未被调用,因为您没有解析在 fetchItem 函数中创建的 Promise

我想为了保持结果的顺序,您可能需要使用 Promise.all。当所有项目都被完全抓取时,它也有助于获得 All done 消息。

我将从更改 fetchPage 函数开始,方法是将 urls 转换为使用 mapfetchItem 承诺数组,我可以将其传递给 Promise.all。像这样

fetchPage(link).then(
    (result)=>{
        const urls=getUrls(result);
        var promises = urls.map((url) => fetchItem(url.link));
        Promise.all(promises).then((values) => { 
            console.log('All done'); 
            console.log(values); 
        }, (error) => { 
            console.log(error); 
        });
    },
    (error)=>console.log(error)
);

然后将 resolve 添加到您的 fetchItem 方法。

function fetchItem(url){
    return new Promise(
        (resolve,reject)=>{
            fetchPage(url).then(
                (result)=>{
                    resolve(getItem(result));
                },
                (error)=>reject(error)
            );
    });
}