我想显示迁移到 mongodb 的操作的进度。
脚本如下:
let promises = [];
mylist.forEach(idx => {
myCollection.find({id: idx}).toArray().then(msgs => {
promises.push(myCollection2.insertMany(msgs.map(msg => ({
msg: msg,
otherFields: others
}))))
})
});
// function to display the progress:
allProgress(promises,
(p) => {
console.log(`% Done = ${p.toFixed(2)}`);
});
function allProgress(proms, progress_cb) {
let d = 0;
progress_cb(0);
proms.forEach((p) => {
p.then(()=> {
d ++;
progress_cb( (d * 100) / proms.length );
});
});
return Promise.all(proms);
}
这是行不通的,因为当 allProgress()
被调用时 promises
是空的。
如何在调用 allProgress()
之前正确收集所有 promise?
更新
在制作一个MCVE的过程中,想到了
let promises = [];
[1,2,3].forEach(idx => {
test(1000).then(promises.push(test(10000)));
});
console.log(promises.length);
// function to display the progress:
allProgress(promises,
(p) => {
console.log(`% Done = ${p.toFixed(2)}`);
});
function test(ms) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(`Waited ${ms}`);
resolve();
}, ms);
});
}
function allProgress(proms, progress_cb) {
let d = 0;
progress_cb(0);
proms.forEach((p) => {
p.then(() => {
d++;
progress_cb((d * 100) / proms.length);
});
});
return Promise.all(proms);
}
令我惊讶的是,这个脚本有效...为什么不等同于我的原始脚本?
更新2
[1,2,3].forEach(idx => {
test(1000).then(_ => {
promises.push(test(10000))
});
});
这个应该是MCVE,不行。
最佳答案
.find() 函数是异步的,因此当您仍在查找元素的过程中时,forEach 循环本身会继续运行。最后,您最终会等待您的 .find()。
你可以做的是在 .then() 回调内部,检查当前 forEach 项目的索引,如果你在最后一项,那么我们知道所有 promise 都已返回。所以在那里调用你的 allProgress 函数。
这应该留出足够的时间等待一切都聚集在一起。此外,通过检查索引,我们知道我们只会在完成时调用您的 allPromises 函数。每个 forEach 循环都不会多次发生。
let promises = [];
mylist.forEach((idx, index) => {
myCollection.find({id: idx}).toArray().then(msgs => {
promises.push(myCollection2.insertMany(msgs.map(msg => ({
msg: msg,
otherFields: others
}))));
if((index + 1) === mylist.length){
// function to display the progress:
allProgress(promises, (p) => {
console.log(`% Done = ${p.toFixed(2)}`);
});
}
})
});
function allProgress(proms, progress_cb) {
let d = 0;
progress_cb(0);
proms.forEach((p) => {
p.then(()=> {
d ++;
progress_cb( (d * 100) / proms.length );
});
});
return Promise.all(proms);
}
编辑: 您的 MCVE(最新编辑)由于完全相同的原因而失败。您的请求是异步的,这允许循环无需等待即可进行。再次检查索引并在完成后调用。
let promises = [];
let entries = [1, 2, 3]
entries.forEach((idx, index) => {
test(1000).then(_ => {
promises.push(test(10000))
if((index + 1) === entries.length) {
console.log(promises.length);
// function to display the progress:
allProgress(promises,
(p) => {
console.log(`% Done = ${p.toFixed(2)}`);
});
}
});
});
function test(ms) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(`Waited ${ms}`);
resolve();
}, ms);
});
}
function allProgress(proms, progress_cb) {
let d = 0;
progress_cb(0);
proms.forEach((p) => {
p.then(() => {
d++;
progress_cb((d * 100) / proms.length);
});
});
return Promise.all(proms);
}
关于javascript - 收集在 forEach 的 promises 中生成的 promises,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54093587/