Собирать обещания, созданные в рамках обещаний в forEach - PullRequest
0 голосов
/ 08 января 2019

Я хочу отобразить ход операции миграции на 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()?


UPDATE

В процессе производства 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 голосов
/ 08 января 2019

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);
}
0 голосов
/ 08 января 2019

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

Edit: Ваш 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...