You could use a variation on the Array#reduce pattern:
array.reduce(
(p, subArray) => p.then(() => Promise.all(subArray)),
Promise.resolve()
);
That sets up a promise chain where each entry in the chain is the result of the promise from Promise.all for the subarrays in the array.
...but:
...where the next array of promises would start resolving ONLY after the previous array of promises have resolved?
That's not how promises work. Once you have the promise, the action it promises a result for is already in progress. You don't "start" it.
So instead, you'd want to make array an array of functions that start the processes in question and return promises, which is slightly different:
function get(label) {
console.log(label + "- starting");
return new Promise(resolve => {
setTimeout(() => {
console.log(label + "- resolving");
resolve(label);
}, Math.random() * 500);
});
}
const array = [
[ get.bind(null, "1a"), get.bind(null, "1b"), get.bind(null, "1c") ],
[ get.bind(null, "2a"), get.bind(null, "2b") ],
[ get.bind(null, "3a"), get.bind(null, "3b"), get.bind(null, "3c"), get.bind(null, "3d") ]
];
array.reduce(
(p, subArray) => p.then(() => Promise.all(subArray.map(f => f()))),
Promise.resolve()
).then(() => {
console.log("All done");
});
.as-console-wrapper {
max-height: 100% !important;
}
Notice how the array is now an array of functions, which when called "start" the process and then return a promise. Our Array#reduce loop is only slightly modified: We use Array#map to call the functions for this subarray and get an array of their promises, which is what we feed into Promise.all. So all of the functions for a given subarray are called to start the work for that subarray, and then we wait unti they're all complete before continuing to the next subarray and having it start its work.