javascript - 收集在 forEach 的 promises 中生成的 promises

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

这是行不通的,因为当 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/

相关文章:

javascript - 需要D3动画画线的说明

mongodb - Mongify Ubuntu 14.04 安装报错

javascript - 如何创建 Mongoose 架构,将输入保存为 mongodb 中的 html

javascript - NodeJs forEach 请求 promise 在返回之前等待所有 promise

javascript - 将 async.eachLimit 转换为 Promise

javascript - Opera Mobile 无法使用 Javascript 聚焦文本输入

javascript - 如何使用 javascript 和基本脚本加载强制不缓存

javascript - Facebook Like 按钮虽然位于隐藏的 div 中,但仍然可见

mongodb - Mongo $OR 嵌套在 $AND 中

javascript - 如何将 Promise 'then' 的值发送到 'catch' ?