Search code examples
javascriptecmascript-6promiseasync-awaitchaining

What's the promise chaining equivalent of awaiting multiple async functions?


I'm studying the usage of promsies and async/await.

I've wrote the following code, which does the following:

  1. It gets some database's data (using Knex.js),
  2. Handles that data,
  3. Assigns the handled data into a specified property.

These 3 steps are done multiple times (In the following code, it's done twice), and are always awaited:

async function run() {
   return await getData();
}
async function getData() {
    let handledData = {};
    handledData.res1 = await knex.select('column1').from('table1').where('column1', '1')
                                 .then(data => handleData(data))
                                 .catch(handleError);
    handledData.res2 = await knex.select('column1').from('table1').where('column1', '2')
                                 .then(data => handleData(data, handledData))
                                 .catch(handleError);
    return handledData;
}
async function handleData(data) {
    let res = [];
    data.forEach(item => {
        res.push(item.column1);
    });
    return res; 
}
function handleError (error) {
    console.log(error);
}

Now, I'm trying to write the promise-chaining equivalent of getData, and this is what I came up with:

async function getData() {
    let handledData = {};
    let promise = new Promise(function(resolve, error){ resolve(); });
    promise
    .then(function () {
        return knex.select('column1').from('table1').where('column1', '1')
                    .then(data => handleData(data))
                    .catch(handleError);
    })
    .then(function(handled){
        handledData.res1 = handled;
        return knex.select('column1').from('table1').where('column1', '2')
                    .then(data => handleData(data))
                    .catch(handleError);
    })
    .then(function(handled){
        handledData.res2 = handled;
        return handledData;
    })
    .catch(handleError);
    return promise;
}

But this doesn't quite work. What happens is that after the first then returns, the await inside run ends its awaiting, which causes run to return - and only then the second then is executed.

How can I make the promise-chaining version work as the multiple-await version does?

(and please, feel free to point out any misunderstaings I made of promises/async-await)


Solution

  • If possible, I'd recommend using Promise.all instead, it'll make your script run faster in addition to making the logic clearer:

    const getData = Promise.all([
      knex.select('column1').from('table1').where('column1', '1')
        // Simply pass the function name as a parameter to the `.then`:
        .then(handleData)
        .catch(handleError),
      knex.select('column1').from('table1').where('column1', '2')
        .then(handleData)
        .catch(handleError)
    ])
      .then(([res1, res1]) => ({ res1, res2 }));