Javascript Node.js:Promise.all(promises)。然后(…)永远不会执行,但程序会完成

Javascript Node.js:Promise.all(promises)。然后(…)永远不会执行,但程序会完成,javascript,node.js,Javascript,Node.js,我在Node.js中使用承诺时遇到问题。我正在使用cheerio和request promise进行web抓取,我希望在所有异步函数执行完毕后,使用promise.all(promises).then(…)语法将结果写入CSV文件。它工作正常,但突然程序完成,没有任何错误或拒绝,但没有执行然后(…)部分(没有文件也没有日志)。这是我的密码: const rp = require('request-promise'); const cheerio = require('cheerio'); con

我在Node.js中使用承诺时遇到问题。我正在使用cheerio和request promise进行web抓取,我希望在所有异步函数执行完毕后,使用
promise.all(promises).then(…)
语法将结果写入CSV文件。它工作正常,但突然程序完成,没有任何错误或拒绝,但没有执行
然后(…)
部分(没有文件也没有日志)。这是我的密码:

const rp = require('request-promise');
const cheerio = require('cheerio');
const csv = require('fast-csv');
const fs = require('fs');

var results = [];
var promises = [];

function getResults(district, branch) {

    for (let i = 65; i <= 90; i++) {

        let letter = String.fromCharCode(i);

        let generalOptions = {
            uri: 'https://ocean.ac-lille.fr/publinet/resultats?previousValCri1=' + branch + '&previousValCri0=0' + district + '&previousIdBaseSession=pub_24&actionId=6&valCriLettre=' + letter,
            transform: function (body) {
                return cheerio.load(body);
            }
        };

        promises.push(new Promise(function(resolve, reject) {
            rp(generalOptions)
                .then(($) => {

                    $('.tableauResultat').find('tr').each(function(i, elem) {
                        let children = $(elem).children('td');
                        let name = $(children[0]).text();

                        results.push({name: name, result: 42, branch: branch});
                        resolve();

                    });
                })
                .catch((err) => {
                    console.log(err);
                    //reject();
                });
            }
        ));
    }
}

getResults(process.argv[2], process.argv[3]);


Promise.all(promises).then(() => {
    console.log("Finished!");
    var ws = fs.createWriteStream('results_bis.csv', {flag: 'w'});
    csv.write(results).pipe(ws);
}).catch((err) => {
    console.log(err);
});
const rp=require('request-promise');
const cheerio=需要(“cheerio”);
const csv=require('fast-csv');
常数fs=要求('fs');
var结果=[];
var承诺=[];
功能getResults(地区、分支机构){
对于(设i=65;i{
$('.tableauResultat').find('tr').each(函数(i,元素){
让children=$(elem.children('td');
让name=$(子项[0]).text();
push({name:name,result:42,branch:branch});
解决();
});
})
.catch((错误)=>{
控制台日志(err);
//拒绝();
});
}
));
}
}
getResults(process.argv[2],process.argv[3]);
承诺。所有(承诺)。然后(()=>{
console.log(“完成!”);
var ws=fs.createWriteStream('results_bis.csv',{flag:'w'});
csv.write(结果).pipe(ws);
}).catch((错误)=>{
控制台日志(err);
});

结果
当与
Promise.all一起使用时,数组通常是反模式。传递给
Promise.all
的承诺将返回必要的结果,因此可以作为
Promise.all(承诺)访问它们。然后(results=>{…})

不需要基于回调的处理,
$('.tableauResultat').find('tr')。每个(…)
,都会导致较差的控制流。由于Cheerio提供了类似于jQuery的API,因此可以将结果转换为数组,并以一种与普通JavaScript惯用的方式进行处理

上面的代码使用promise构造反模式。如果存在一个
rp(通用选项)
,则不需要
新承诺。它加剧了这个问题;Node.js在没有计划执行的情况下存在。
promise
中的某些承诺处于挂起状态,无法解决,因为既没有调用
resolve
也没有调用
reject
。如果每次
回调从未触发,则会发生这种情况。通过将
resolve()
移动到
每个
回调之外,可以解决此问题

这是一种更简单的方法,可以减少不明确的问题,并且更易于调试:

const promises = [];

function getResults(district, branch) {
    for (let i = 65; i <= 90; i++) {
        ...
        promises.push(
            rp(generalOptions)
            .then(($) => {
                const trs = $('.tableauResultat').find('tr').toArray();
                const results = trs.map(elem => {
                    let children = $(elem).children('td');
                    let name = $(children[0]).text();

                    return {name, result: 42, branch};
                });

                return results;
            })
            .catch((err) => {
                console.log(err);
                return null; // can be filtered out in Promise.all results
                // or rethrow an error
            })    
        );
    }
}

getResults(...);

Promise.all(promises).then(nestedResults => {
    const results = nestedResults.reduce((flatArr, arr) => flatArr.concat(arr), []);
    console.log("Finished!");
    var ws = fs.createWriteStream('results_bis.csv', {flag: 'w'});
    csv.write(results).pipe(ws);
}).catch((err) => {
    console.log(err);
});
const promises=[];
功能getResults(地区、分支机构){
对于(设i=65;i{
常量trs=$('.tableauResultat').find('tr').toArray();
常量结果=trs.map(元素=>{
让children=$(elem.children('td');
让name=$(子项[0]).text();
返回{name,result:42,branch};
});
返回结果;
})
.catch((错误)=>{
控制台日志(err);
return null;//可以在Promise中过滤掉。所有结果
//或者重发一个错误
})    
);
}
}
getResults(…);
Promise.all(promises).then(nestedResults=>{
const results=nestedResults.reduce((flatArr,arr)=>flatArr.concat(arr),[]);
console.log(“完成!”);
var ws=fs.createWriteStream('results_bis.csv',{flag:'w'});
csv.write(结果).pipe(ws);
}).catch((错误)=>{
控制台日志(err);
});

请注意,当前未处理来自文件流的错误。
承诺不太可能。即使存在问题,所有
捕获都将被触发。

我相信您的节点应用程序可能会在不等待承诺解决的情况下结束。尝试以下解决方案之一我对您的代码没有问题,除了未定义
someObject
。节点v8.11.1,npm 5.6。0@AndrewParamoshkin是的,这是因为我在发布代码之前简化了代码:someObject是一个从cheerio:)@RyanC收集的数据创建的对象,我使用了
process.stdin.resume()解决方案,现在我的程序从未完成(但
然后(…)
仍然没有执行)。。。这很奇怪,因为当我记录推送到
results
的数据时,所有的承诺似乎都解决了,根本没有控制台输出?很难相信。至少应该有一些。console.log不是调试脚本的有效方法,您无法看到空条目。您不需要
process.stdin.resume()
。如果有悬而未决的承诺,该计划将不会退出。您拒绝时出现空错误
reject()
,根本不需要
新承诺。这是promise构造反模式。另外
,函数(err){console.log(err);})
不会捕获
中发生的错误,然后使用
捕获
。请提供可以复制问题的方法。很高兴它有帮助。