代码之家  ›  专栏  ›  技术社区  ›  Siyu Zeeshan Akhter

收集在foreach中的承诺中生成的承诺

  •  1
  • Siyu Zeeshan Akhter  · 技术社区  · 6 年前

    我想显示到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() 被称为。

    打电话前我怎么能正确地收回所有的承诺? 所有进展() ?


    更新

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

    2 回复  |  直到 6 年前
        1
  •  2
  •   basic    6 年前

    .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);
    }
        2
  •  0
  •   zhenyu wu    6 年前

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