正确的方法来堆栈选项承诺

用承诺收集来自数据库的所有数据的适当或最好的方法是什么,但使用本地Node承诺。

目标只是提出select什么:

 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()... }); 

可能的解决scheme:

  • 所选数据的轨迹索引(例如,C的索引将为1)
  • 对象映射
  • 添加其他{ allPromises.push(Promise.resolve(null)) }给每个if

有没有更容易或这其中一个将是正确的方式?

不要有条件地使用数组,但始终将相同的值放在同一个索引处。 即使这个价值没有任何意义 – Promise.all将会处理得很好。

 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 } }); 

你怎么看待这件事 ? 它更大,更重,更困难,但它都是自动化和完全演化的 。 想要处理一个新的参数? 一个参数现在有数据? 仅更改地图。


我创build了一个包含我们需要使用循环的所有东西的地图。 数据的状态(激活与否),调用获取数据的函数等。

 const mapSelected = { sectionA: { state: true, func: getSectionADataFromDbPromise, }, sectionB: { state: false, func: getSectionBDataFromDbPromise, }, sectionC: { state: true, func: getSectionCDataFromDbPromise, data: [ 1, 2, 4, ], }, }; 

然后我们使用我们创build的地图创buildpromise数组。 处理与数据和没有数据的情况。

 const promises = Object.values(mapSelected).reduce((tmp, { state, func, data, }) => { if (!state) return tmp; if (data && data.length) { return [ ...tmp, ...data.map(x => func.call(this, x)), ]; } return [ ...tmp, func.call(this), ]; }); 

然后我们根据地图上每个键的promise返回来创build数组。 你可以改变我如何呈现数据,我不知道你在那里想要什么。

 Promise.all(promises) .then((allResults) => { let i = 0; const [ dataA, dataB, dataC, ] = Object.values(mapSelected).reduce((tmp, { state, data, }, xi) => { if (!state) return tmp; if (data && data.length) { data.forEach(x => (tmp[xi].push(allPromises[i++]))); return tmp; } tmp[xi].push(allPromises[i++]); return tmp; }, Object.values(mapSelected).map(() => [])); }); 


@编辑

我只是做了一个关于我已经做的代码片段,运行它

 function a() { return 1; } const mapSelected = { sectionA: { state: true, func: a, }, sectionB: { state: false, func: a, }, sectionC: { state: true, func: a, data: [ 1, 2, 4, ], }, }; const allPromises = [ 0, 1, 2, 3, 4, ]; let i = 0; const [ dataA, dataB, dataC, ] = Object.values(mapSelected).reduce((tmp, { state, data, }, xi) => { if (!state) return tmp; if (data && data.length) { data.forEach(x => (tmp[xi].push(allPromises[i++]))); return tmp; } tmp[xi].push(allPromises[i++]); return tmp; }, Object.values(mapSelected).map(() => [])); console.log(dataA); console.log(dataB); console.log(dataC); 

不幸的是,不像Q这样的图书馆,标准的Promise并没有公开一个承诺的对象的变种。

但是,我们可以使用新的ES2015和ES2017 Object实用程序方法来帮助我们保持代码的可读性。

 const allPromises = {}; const selected = { sectionA: true, sectionB: false, sectionCIds: [1, 2, 4], }; if (selected.sectionA) { allPromises.sectionA = getSectionADataFromDbPromise(); } if (selected.sectionB) { allPromises.sectionB = getSectionBDataFromDbPromise(); } if (selected.sectionBIds.length > 0) { allPromises.sectionC = Promise.all(selected.sectionBIds .map(getSectionCDataFromDbPromise) ); } 

现在我们可以写

 Promise.all(Object.entries(allPromises).map(([key, promise]) => promise.then(value => ({[key]: value})) )) .then(allResults => { const results = Object.assign({}, ...allResults); const data = { a: results.sectionA, b: results.sectionB, c: results.sectionB && results.sectionC }; // ... same logic to build report: return Promise.all()... });