Home:ALL Converter>The proper ways to stack optioned promises

The proper ways to stack optioned promises

Ask Time:2017-11-24T17:30:34         Author:Vladimir Vukanac

Json Formatter

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?

Author:Vladimir Vukanac,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/47470147/the-proper-ways-to-stack-optioned-promises
Bergi :

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.\n\nconst selected = {\n sectionA: true,\n sectionB: false,\n sectionCIds: [ 1, 2, 4 ],\n};\nPromise.all([\n selected.sectionA ? getSectionADataFromDbPromise() : null,\n selected.sectionB ? getSectionBDataFromDbPromise() : null,\n Promise.all(selected.sectionCIds.map(getSectionCDataFromDbPromise))\n]).then(([dataA, dataB, dataC]) => {\n if (selected.sectionA) {\n // use dataA\n }\n if (selected.sectionA) {\n // use dataB\n }\n if (dataC.length) { // same as selected.selectionCIds.length\n // use dataC\n }\n});\n",
2017-11-24T10:28:44
Orelsanpls :

What do you think about this ? It's bigger, it's heavier, it's more difficult, but it's all automatized and fully evolutive. Wanna handle a new parameter ? A parameter have data now ? Change the map only.\n\n\n\nI create a map that would contains everything we need to use a loop. The state of the data (activated or not), the function to call to get the data and so on.\n\nconst mapSelected = {\n sectionA: {\n state: true,\n\n func: getSectionADataFromDbPromise,\n },\n\n sectionB: {\n state: false,\n\n func: getSectionBDataFromDbPromise,\n },\n\n sectionC: {\n state: true,\n\n func: getSectionCDataFromDbPromise,\n\n data: [\n 1,\n 2,\n 4,\n ],\n },\n};\n\n\n\n\nThen we create the promise array using the map we has created. Handling the case with data and without data.\n\nconst promises = Object.values(mapSelected).reduce((tmp, {\n state,\n func,\n data,\n}) => {\n if (!state) return tmp;\n\n if (data && data.length) {\n return [\n ...tmp,\n\n ...data.map(x => func.call(this, x)),\n ];\n }\n\n return [\n ...tmp,\n\n func.call(this),\n ];\n});\n\n\n\n\nThen we create arrays from the promise return for each key on the map. You can change how I present the data, I didn't knew what you really wanted there.\n\nPromise.all(promises)\n .then((allResults) => {\n let i = 0;\n\n const [\n dataA,\n dataB,\n dataC,\n ] = Object.values(mapSelected).reduce((tmp, {\n state,\n data,\n }, xi) => {\n if (!state) return tmp;\n\n if (data && data.length) {\n data.forEach(x => (tmp[xi].push(allPromises[i++])));\n\n return tmp;\n }\n\n tmp[xi].push(allPromises[i++]);\n\n return tmp;\n }, Object.values(mapSelected).map(() => []));\n });\n\n\n\n\n\n\n@EDIT\n\nI just did a snippet about the code I've made, run it\n\n\r\n\r\nfunction a() {\r\n return 1;\r\n}\r\n\r\nconst mapSelected = {\r\n sectionA: {\r\n state: true,\r\n\r\n func: a,\r\n },\r\n\r\n sectionB: {\r\n state: false,\r\n\r\n func: a,\r\n },\r\n\r\n sectionC: {\r\n state: true,\r\n\r\n func: a,\r\n\r\n data: [\r\n 1,\r\n 2,\r\n 4,\r\n ],\r\n },\r\n};\r\n\r\nconst allPromises = [\r\n 0,\r\n 1,\r\n 2,\r\n 3,\r\n 4,\r\n];\r\n\r\nlet i = 0;\r\n\r\nconst [\r\n dataA,\r\n dataB,\r\n dataC,\r\n] = Object.values(mapSelected).reduce((tmp, {\r\n state,\r\n data,\r\n}, xi) => {\r\n if (!state) return tmp;\r\n\r\n if (data && data.length) {\r\n data.forEach(x => (tmp[xi].push(allPromises[i++])));\r\n\r\n return tmp;\r\n }\r\n\r\n tmp[xi].push(allPromises[i++]);\r\n\r\n return tmp;\r\n}, Object.values(mapSelected).map(() => []));\r\n\r\nconsole.log(dataA);\r\nconsole.log(dataB);\r\nconsole.log(dataC);",
2017-11-24T09:59:16
yy