Node.js:Promise.all(promises).then(...)从未执行,但程序已完成

时间:2018-07-20 09:54:17

标签: javascript node.js

我在使用Node.js的Promise时遇到问题。我正在使用cheerio和request-promise进行Web抓取,并且我想在使用Promise.all(promises).then(...)语法执行了所有异步函数后,将结果写入CSV文件。它运行正常,但突然程序完成,没有任何错误或被拒绝,但没有执行then(...)部分(没有文件,也没有日志)。这是我的代码:

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);
});

1 个答案:

答案 0 :(得分:1)

results一起使用时,

Promise.all数组通常是反模式。预期传递给Promise.all的诺言会返回必要的结果,因此可以以Promise.all(promises).then(results => { ... })的形式访问它们。

不需要基于回调的处理$('.tableauResultat').find('tr').each(...),这会导致控制流不佳。由于Cheerio提供了类似jQuery的API,因此可以将结果转换为数组并以原始JavaScript特有的方式进行处理。

上面的代码使用promise构造反模式。如果有一个new Promise,则不需要rp(generalOptions)。它导致了问题;没有计划执行的时间时,Node.js存在。 promise中的某些promise正在等待执行,因为resolvereject都没有被调用,所以它们没有机会被解决。如果从未触发each回调,则会发生这种情况。可以通过将resolve()移到each回调之外来解决此问题。

一种更直接的方法,可以为模糊的问题留出更少的空间,并且更易于调试:

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);
});

请注意,当前未处理来自文件流的错误。即使有问题,也不会触发Promise.all catch