First, let’s celebrate this site runs for more than a year! In case you don’t know, I removed the Google Analytics last month, cuz I don’t need it to remind me no one reads my blog.

Now back to the main point. Here is the problem:

const timeout = ms => new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve();
    }, ms);
});

const ajax1 = () => timeout(2000).then(() => {
    console.log('1');
    return 1;
});

const ajax2 = () => timeout(1000).then(() => {
    console.log('2');
    return 2;
});

const ajax3 = () => timeout(2000).then(() => {
    console.log('3');
    return 3;
});

const mergePromise = ajaxArray => {
    // your code here
};

mergePromise([ajax1, ajax2, ajax3]).then(data => {
    console.log('done');
    console.log(data);
});

// output should be:
// 1
// 2
// 3
// done
// [1, 2, 3]

If we use Promise.all() here, the final array is correct, but the promises won’t run in order:

const mergePromise = ajaxArray => Promise.all(ajaxArray.map((arr) => arr()));
// 2
// 1
// 3
// done
// [1, 2, 3]

Don’t panic! reduce() gonna save the day.

// accumulator p: Promise object
// currentValue f: function
// initialValue: Promise.resolve()
const mergePromise = ajaxArray => ajaxArray.reduce((p, f) => p.then(f), Promise.resolve());
// 1
// 2
// 3

Then we need to store the return value:

const mergePromise = ajaxArray => ajaxArray.reduce((p, f) => p.then((pResult => f().then(fResult => [...pResult, fResult]))), Promise.resolve([]));
// 1
// 2
// 3
// done
// [1, 2, 3]

You see, I learned something today. Never make a promise casually.

See also