Search code examples
javascriptnode.jspromisees6-promise

The proper ways to stack optioned promises


What would be the proper or the best way to collect all data from DB with promises, but with using native Node promises.

The goal is only to present what is selected:

const allPromises = [];
const selected = {
  sectionA: true,
  sectionB: false,
  sectionCIds: [ 1, 2, 4 ],
};

if (selected.sectionA) {
  allPromises.push(getSectionADataFromDbPromise());
}
if (selected.sectionB) {
  allPromises.push(getSectionBDataFromDbPromise());
}
if (selected.sectionCIds.length > 0) {
  allPromises.push(selected.sectionCIds
    .map(getSectionCDataFromDbPromise)
  );
}
Promise.all(allPromises)
  .then((allResults) => {
    if (selected.sectionA) {
      dataA = allResults[0];
    }
    if (selected.sectionA) {
      dataB = allResults[1];
    }
    if (selected.sectionC) {
      dataC = allResults[2]; // <-- this will not work if B is not selected
    }

    // ... same logic to build report: return Promise.all()...
  });

Possible solutions:

  • Track index for each data selected (eg. index of C will be 1)
  • Object Map
  • Add else { allPromises.push(Promise.resolve(null)) } to every if

Is there maybe an easier or one of this will be the proper way?


Solution

  • Don't use push on the arrays conditionally, but always put the same value at the same index. Even if the value is nothing - Promise.all will handle that just fine.

    const selected = {
      sectionA: true,
      sectionB: false,
      sectionCIds: [ 1, 2, 4 ],
    };
    Promise.all([
      selected.sectionA ? getSectionADataFromDbPromise() : null,
      selected.sectionB ? getSectionBDataFromDbPromise() : null,
      Promise.all(selected.sectionCIds.map(getSectionCDataFromDbPromise))
    ]).then(([dataA, dataB, dataC]) => {
      if (selected.sectionA) {
        // use dataA
      }
      if (selected.sectionA) {
        // use dataB
      }
      if (dataC.length) { // same as selected.selectionCIds.length
        // use dataC
      }
    });