收集在forEach中的承诺内产生的承诺

时间:2019-01-08 14:09:21

标签: javascript mongodb promise

我想显示向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);
}

这不起作用,因为在调用promisesallProgress()为空。

在致电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,它不起作用。

2 个答案:

答案 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);
}