我在 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 处于未决状态,它们没有机会被解决,因为 resolve
和 reject
都没有被调用。如果永远不会触发 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/