Promise inside promise

通りすがりのおっさん picture 通りすがりのおっさん · Jun 1, 2016 · Viewed 10.8k times · Source

I am trying to write this code with Promise. but I don't know how to write promise inside Promise and loop. I tried to think like this but insertBook function become asynchronously. How can I get bookId synchronously?

update: function(items, quotationId) {
  return new Promise(function(resolve, reject) {
    knex.transaction(function (t) {
      Promise.bind(result).then(function() {
        return process1
      }).then(function() {
        return process2
      }).then(function() {
        var promises = items.map(function (item) {
          var people = _.pick(item, 'familyName', 'firstNumber', 'tel');
          if (item.type === 'book') {
            var book = _.pick(item, 'name', 'bookNumber', 'author');
            var bookId = insertBook(t, book);
            var values = _.merge({}, people,  {quotation: quotationId}, {book: bookId});
          } else {
            var values = _.merge({}, people,  {quotation: quotationId});
          }
          return AModel.validateFor(values);
        });
        return Promise.all(promises);
      }).then(function(items) {
        var insertValues = items.map(function (item) {
          return People.columnize(item);
        });
        return knex('people').transacting(t).insert(insertValues);
      }).then(function() {
        return process5
      }).then(function() {
        ...........

      }).then(function() {
        t.commit(this);
      }).catch(t.rollback);
    }).then(function (res) {
      resolve(res);
    }).catch(function(err) {
      reject(err);
    });
  });
}

function insertBook(t, book){
  return Promise.bind(this).then(function () {
    return Book.columnizeFor(book);
  }).then(function (value) {
    return knex('book').transacting(t).insert(value, "id");
  });
}

Answer

Tamas Hegedus picture Tamas Hegedus · Jun 1, 2016

You dont need to get bookid synchronously, you can handle it asynchronously correctly. Also, it is possible you want all book insertions happen sequentially, so I refactored the Promise.all part. (done that just to give you an idea. Promise.all should work fine if insertions in parallel are allowed). Furthermore, I think you shouldn't use Promise.bind. To be honest I dont even know what it does, one thing for sure: it doesn't work with standard promises. So here is an example how I think it should work:

update: function(items) {
  return new Promise(function(resolve) {
    knex.transaction(function (t) {
      resolve(Promise.resolve().then(function() {
        return process1;
      }).then(function() {
        return process2;
      }).then(function() {
        var q = Promise.resolve(), results = [];
        items.forEach(function (item) {
          q = q.then(function() {
            var book = _.pick(item, 'name', 'bookNumber', 'author');
            return insertBook(t, book);
          }).then(function(bookId) {
            var people = _.pick(item, 'familyName', 'firstNumber', 'tel');
            var values = _.merge({}, people,  {book: bookId});
            return AModel.validateFor(values);
          }).then(function(item) {
            results.push(item);
          });
        });
        return q.then(function() {
          return results;
        });
      }).then(function(items) {
        return process4
      }).then(function() {
        t.commit(result);
      }).catch(function(e) {
        t.rollback(e);
        throw e;
      }));
    });
  });
}

function insertBook(t, book){
  return Promise.resolve().then(function () {
    return Book.columnizeFor(book);
  }).then(function (value) {
    return knex('book').transacting(t).insert(value, "id");
  });
}