我想显示向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);
}
这不起作用,因为在调用promises
时allProgress()
为空。
在致电allProgress()
之前如何正确收集所有的诺言?
更新
在制作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);
}
令我惊讶的是,此脚本有效……为什么不等同于我的原始脚本?
UPDATE2
[1,2,3].forEach(idx => {
test(1000).then(_ => {
promises.push(test(10000))
});
});
这应该是MCVE,它不起作用。
答案 0 :(得分:2)
.find()函数是异步的,因此当您仍在查找元素的过程中,forEach循环本身将继续前进。最后,您最终要等待.find()。
您可以在.then()回调内部进行操作,检查当前forEach项目的索引,如果您位于最后一个项目,则我们知道所有诺言都已返回。因此,在此处调用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);
}
答案 1 :(得分:0)
myCollection.find({id:idx})是异步操作。 所以你可以这样:
let promises = [];
mylist.forEach(idx => {
myCollection.find({id: idx}).toArray().then(msgs => {
promises.push(myCollection2.insertMany(msgs.map(msg => ({
msg: msg,
otherFields: others
}))))
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);
}