javascript - Promise.then 在前一个 .then 之前被解决,foreach 完成
问题描述
我正在运行一个半复杂的承诺链,中间有一个 foreach 循环。我遇到的问题是 final.then()
在 foreach 循环完成之前被击中,导致一个完全空的dailyTotals
数组。
fs.readdir(csvPath)
.then(files => {
// Define storage array
var csvFiles = [];
// Loop through and remove non-csv
files.forEach(file => {
if (file !== "README.md" && file !== ".gitignore") {
csvFiles.push(file);
}
});
return csvFiles;
})
.then(files => {
var dailyTotals = [];
files.forEach(filename => {
const loadedFile = fs.createReadStream(csvPath + filename);
var totalCases = 0;
var totalDeaths = 0;
var totalRecovered = 0;
papa.parse(loadedFile, {
header: true,
worker: true,
step: r => {
totalCases += parseIntegerValue(r.data.Confirmed);
totalDeaths += parseIntegerValue(r.data.Deaths);
totalRecovered += parseIntegerValue(r.data.Recovered);
},
complete: () => {
var dailyTotal = {
date: filename.replace(".csv", ""),
parsed: {
confirmed: totalCases,
deaths: totalDeaths,
recovered: totalRecovered
}
};
dailyTotals.push(dailyTotal);
}
});
});
return dailyTotals;
})
.then(dailyTotals => {
console.log(dailyTotals);
});
有没有办法在解决下一个之前等待该 foreach 循环完成.then()
?问题直接在foreach和final上console.log(dailyTotals);
解决方案
首先,我不得不提一下,还有一些替代方法Array#forEach
:
Array#map
它旨在通过映射原始数组(与您所做的相同.forEach
)来创建一个新数组,并且Array#filter
(它的名字不言自明)。
问题是,你有一个承诺链和一个基于回调的模块。要混合它们,请使用Promise
构造函数并使用Promise.all
, 将它们组合成一个 Promise:
fs.readdir(csvPath)
.then(files => {
// Filter out non-csv
return files.filter(file => (file !== "README.md" && file !== ".gitignore"))
})
.then(files => {
//Returning a Promise from then handler will be awaited
return Promise.all(files.map(filename => {
const loadedFile = fs.createReadStream(csvPath + filename);
return new Promise(resolve => {
var totalCases = 0;
var totalDeaths = 0;
var totalRecovered = 0;
papa.parse(loadedFile, {
header: true,
worker: true,
step: r => {
totalCases += parseIntegerValue(r.data.Confirmed);
totalDeaths += parseIntegerValue(r.data.Deaths);
totalRecovered += parseIntegerValue(r.data.Recovered);
},
complete: () => {
resolve( {
date: filename.replace(".csv", ""),
parsed: {
confirmed: totalCases,
deaths: totalDeaths,
recovered: totalRecovered
}
});
}
});
});
}));
})
.then(dailyTotals => {
console.log(dailyTotals);
});
您甚至可以省略第一个 .then
处理程序,就像.filter
同步操作一样,并在单个 中执行所有操作.then
:
fs.readdir(csvPath)
.then(files => {
//Returning a Promise from then handler will be awaited
return Promise.all(
files
//Filter here
.filter(file => (file !== "README.md" && file !== ".gitignore"))
//And map without a second then
.map(filename => {
const loadedFile = fs.createReadStream(csvPath + filename);
return new Promise(resolve => {
var totalCases = 0;
var totalDeaths = 0;
var totalRecovered = 0;
papa.parse(loadedFile, {
header: true,
worker: true,
step: r => {
totalCases += parseIntegerValue(r.data.Confirmed);
totalDeaths += parseIntegerValue(r.data.Deaths);
totalRecovered += parseIntegerValue(r.data.Recovered);
},
complete: () => {
resolve( {
date: filename.replace(".csv", ""),
parsed: {
confirmed: totalCases,
deaths: totalDeaths,
recovered: totalRecovered
}
});
}
});
});
})
);
})
.then(dailyTotals => {
console.log(dailyTotals);
});