[英]Promise.then being resolved before previous .then with foreach completes
我正在运行一个半复杂的 promise 链,中间有一个 foreach 循环。 我遇到的问题是最终的.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);
});
有没有办法在解析到下一个.then()
之前等待该 foreach 循环完成? 问题直接在 foreach 和最终的console.log(dailyTotals);
不,您不会让您的 promise 在返回之前等待.forEach
。 如果您的.forEach
function 包含异步代码,则不应使用它。 相反,您可以使用稍微不同的方法 go :
.map
,类似于您所做的。 forEach
,我建议如下:const promises = [array with your values].map(() => {
// If you are running in a node env, you can also make the function async instead of returning a promise
return new Promise((resolve, reject) => {
// Do what you need to
if (error) {
reject(error);
}
resolve(<insert the value that should be returned here>);
});
});
Promise.all(promises).then(() => console.log('all promises done'));
使用一些简单的 console.log 查看一个工作示例: https://jsfiddle.net/3ghmsaqj/
首先,我不得不提到Array#forEach
有一些替代方法:
Array#map
旨在通过映射原始数组来创建一个新数组(与您对.forEach
所做的相同),以及Array#filter
(它的名字不言自明)。 问题是,你有一个 promise 链和一个基于回调的模块。 要混合它们,请使用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);
});
看起来你的第二个then
有异步代码papa.parse()
所以你的 for each 在第二个then
将使用空值同步完成,因此最后一个then
将使用这些空值执行。 您只需要从第二个返回then
在异步代码完成时阻塞
您必须在complete
回调中解决承诺,并使用Promise.all
之类的方法来检测何时执行所有complete
回调
1)将您的每个更改为 map..
const arrayPromises= files.map(... Etc)
2) 从您的 map 回调中返回 promise。
files.map((file) => new Promise((resolve, reject) => {... Everything from your current foraeach}))
3)从complete
的回调中旋转您的 promise
reolve()
4) 使用return Promise.all(arrayPromises)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.