Использование каждого значения обещания Promise.map в качестве ввода следующего цикла - PullRequest
0 голосов
/ 30 ноября 2018

Я провел целый день исследование о том, как я могу получить результат каждого обещания в Promise.map и использовать его в качестве входных данных на следующей итерации в цикле того же Promise.mapстрого должен сделать этот подход, потому что я использую эту логику в операции с базой данных , что должно быть ATOMIC , и в случае отклонения любого обещания все предыдущие транзакции имеютоткат.

ПРИМЕЧАНИЕ: Я использовал promise.each, и он работает хорошо только потому, что он не позволяет мне связать отдельные обещания и откат все если не получится.Так что Promise.map представляется наилучшим решением, когда каждое обещание тщательно разрешено и значение возвращено, не вызывая Error: Transaction query already complete в следующем цикле.Вот логика с knex:

var obj={};

knex.transaction(function(trx) {
  return Promise.map(array, function(item) {
        return trx.insert(item).into('table')
        .then(returnedFields => {
        //do some validation/operation and return the result or the returnedFields themselves as input in the next loop.
        //[START EDIT: this responds to comment by @ Mikael Lepistö for clarity]
        //update obj here to be used in next loop
        //[END EDIT]
      });
    }, {concurrency: 1});
})
.then(function(inserts) {
  console.log(inserts.length + 'Items saved.');
})
.catch(function(error) {
  console.error(error);
})

Ответы [ 3 ]

0 голосов
/ 30 ноября 2018

Вы можете проверить async.js библиотека https://caolan.github.io/async/docs.html

Вот что вы можете сделать

knex.transaction(function(trx) {
    return async.mapValuesSeries(array, (item) => {
        return trx.insert(item).into('table')
        .then(returnedFields => {
        //do some validation/operation and return the result or the returnedFields themselves as input in the next loop.
        });
    }, (error, inserts) => {
        if (err) { 
            console.error(error);
        }
        console.log(inserts.length + 'Items saved.');
    });
});
0 голосов
/ 30 ноября 2018

Спасибо всем, кто опубликовал большие / большие идеи.Однако оказалось, что Promise.each хорошо работает с knex, и я допустил ошибку, вызвав commit внутри then какого-то отдельного promises во время цикла, что вызвало Error: Transaction query already complete при следующей попытке транзакциипоследующий цикл. Причина: Не было необходимости вызывать commit с контекстом / блоком транзакции knex, так как он автоматически запускается в этом контексте.

Чтобы отметить ответ ниже:

Использование Knex с Promise.each требует от вас прослушивания возможного отклонения внутри блока then каждого обещания и с try/catch, а в некоторых случаях явного отклонения , в противном случае последующиеОбещания / значения будут продолжать цикл, и это не может сделать базу данных атомарной !!!

knex.transaction(function(trx) {
  return Promise.map(array, function(item) {
        return trx.insert(item).into('table')
        .then(returnedFields => {
        try{
        //do some validation/operation and return the result or the returnedFields themselves as input in the next loop.
        /* START Testing a case of rejection */
           if (array.indexOf(item) === 3) {
               //uncomment the code below to test
               //throw new Error('BreakException');
            }
        /* END */
        }catch(err){
        fail=true;
        }
      }).then(val => {
          if (fail) {
            trx.rollback()//you can ignore this as is automatically triggered here - tested
            return Promise.reject(new Error('Rejected'))
          }
          return val
        })
        .catch(err => {
          fail = true
          trx.rollback()//you can ignore this as is automatically triggered here - tested
          return Promise.reject(new Error('Rejected'))
        });
    });
})
.then(function(inserts) {
  console.log(inserts.length + 'Items saved.');
})
.catch(function(error) {
  console.error(error);
})
0 голосов
/ 30 ноября 2018

Проверьте это:

var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

...