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

标签 javascript node.js

我在 Node.js 中使用 promises 时遇到问题。我正在使用 cheerio 和 request-promise 进行网络抓取,我想在所有异步函数执行完毕后将结果写入 CSV 文件,使用 Promise.all(promises).then(...) 语法。它工作正常但突然程序完成而没有任何错误或拒绝但没有执行 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);
});

最佳答案

results 数组在与 Promise.all 一起使用时通常是一个反模式。预计传递给 Promise.all 的 promise 会返回必要的结果,因此可以作为 Promise.all(promises).then(results => { ... }) 访问它们

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

上面的代码使用了 promise 构造反模式。如果存在 rp(generalOptions),则无需 new Promise。它助长了这个问题;当没有计划执行时,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 也不太可能被触发。

关于javascript - Node.js:Promise.all(promises).then(...) 从未执行但程序完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51439919/

相关文章:

javascript - 将 RequireJs 与自定义 JS 插件结合使用

javascript - Summernote 在 POST 中添加 "files"字段

node.js - Mocha + Supertest 中 404 测试的“Body Parse”错误

node.js - React 中 fetch 不返回数据

node.js - Node.JS、Socket.IO 和集群中的 WebSocket 握手不起作用

javascript - 需要将一个数组中的对象值与另一个数组中的对象值相匹配

javascript - 当固定 DIV 滚动到另一个 HTML 元素时动态添加 CSS 类

javascript - 将多个常量导出为一个 json

javascript - 一页上有两个滑动 slider

javascript - JSDoc - 指定强制参数语法