обещания внутри для цикла - PullRequest
0 голосов
/ 27 апреля 2020

игнорировать синтаксическую ошибку. Мне нужно выполнить кое-что со значением i внутри агрегата и обновить его, но когда я выполняю приведенный ниже код, for l oop не ожидает завершения sh до обновления .it итерирует значение i очень быстро, и агрегат пропускает каждое значение i. Я новичок в javascript, поэтому, если вопрос глупый извините за это тоже

model.countDocuments((err,count)=>{    
for(i=value;i<count;i++){
     console.log(i)
     model.aggregate({[//some update function]})
     .then((res)=>model.update({field:something},{$set:res.value}}))
})

Ответы [ 2 ]

1 голос
/ 28 апреля 2020

Вы можете использовать Promise.all, чтобы по-прежнему выполнять большую часть своей работы одновременно и получать результаты, когда они все будут выполнены, в том же порядке, в котором вы их запустили. Вот полностью рабочий пример, который несколько напоминает вашу проблему.

// Generate a random value between 250 and 500. Used for the delay to setTimeout 
// to mimic "long running" operations.
const delay = () => Math.floor(Math.random()*(500 - 250 + 1))+250;

// This represents your model.aggregate function. Takes an input of a number for
// the sake of correlation in this example. Always resolves a string with the
// intention of passing it into the next "then."
const aggregate = (i) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => { resolve(`[${i}]: aggregated`) }, delay());
  });
};

// This represents your model.update function. Takes a number for the sake of
// correlation and the result from the "aggregate" function.
const update = (i, res) => {
  // result from aggregate
  console.log(`[${i}]: ${res}`);

  return new Promise((resolve, reject) => {
    setTimeout(() => { resolve(`[${i}]: updated`) }, delay());
  });
};

// A helper to generate an array of numbers. Just a "fancier" alternative to
// "for i=value; i<count; i++"
const range = (i) => [...Array(i).keys()]

// An arbitrary number for the amount of work to run in this example. This 
// represents "count" in your example.
const count = 10;

// This is the equivalent of what would be your for loop's body. Executes "count"
// amount of work and stores all the the promises into an array. Even though we
// have a list of promises in the array, this is non-blocking and the program will
// continue until we wait for them to all resolve later.
const res = range(count).map((i) => {
  console.log(`[${i}]: starting`);
  return aggregate(i).then((res) => update(i, res));
});

// Wait for all promises to resolve and print the final results. At this
// exact moment, some be still running and some may have completed.
// Call then will let you get the results of all the work when they are
// are all resolved.
//
// The block in "catch" will be called when any one of them "rejects" or
// throws an exception.
Promise.all(res).
  then((vals) => { for (const val of vals) { console.log(val) } }).
  catch((err) => { console.error(err) });

Вот пример выходных данных:

[0]: starting
[1]: starting
[2]: starting
[3]: starting
[4]: starting
[5]: starting
[6]: starting
[7]: starting
[8]: starting
[9]: starting
[6]: [6]: aggregated
[2]: [2]: aggregated
[4]: [4]: aggregated
[7]: [7]: aggregated
[9]: [9]: aggregated
[3]: [3]: aggregated
[0]: [0]: aggregated
[1]: [1]: aggregated
[8]: [8]: aggregated
[5]: [5]: aggregated
[0]: updated
[1]: updated
[2]: updated
[3]: updated
[4]: updated
[5]: updated
[6]: updated
[7]: updated
[8]: updated
[9]: updated

Обратите внимание, что конечные выходные данные находятся в том же порядке, что и их запуск ( От 0 до 9). Однако «агрегат» и «обновление» по-прежнему выполняются асинхронно.

Дело в том, что вам не нужно ждать запуска первого вызова «агрегат затем обновление» для fini sh следующий «агрегат, затем обновление», затем следующий «агрегат, затем обновление» после этого и так далее. Довольно сильно выбрасывая "асинхронность" в окно. Использование async / await определенно имеет свое место (и я их часто использую), но я бы сказал, что это не лучшее место для его использования.

1 голос
/ 27 апреля 2020

Попробуйте использовать функцию async / await

Измените свой код на этот

model.countDocuments(async (err,count)=>{    
    for(i=value;i<count;i++){
         console.log(i);
         let res = await model.aggregate({[/*some update function]*/});
         model.update({field:something},{$set:res.value}});
    }
)

Использование ключевого слова await заставит код ждать возврата обещания и продолжать выполнение следующего оператора.

Чтобы использовать ключевое слово 'await', включающая функция должна объявить себя как 'asyn c' функция

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...