Skip to content Skip to sidebar Skip to footer

Async.parallel To Async Await - Node.js

I am using express-promise-router to achieve async/await in my query calls from node.js. Sometimes, when I need to fetch data for tables, I use async.parallel to get the data as we

Solution 1:

I tried to keep the code similar to what you have above, but I noticed at the end that you're using a higher level result object to pass references around.

In the below code, I'm not using async/await since that's not entirely necessary for this example since the pool.query method takes a callback. Instead, I created rows and count functions that return Promises. Then I use those with Promise.all which will let both promises run in parallel and return the results as an array in the same order the promises are passed to Promise.all. See further down for an example using async/await when pool.query returns a promise instead.

router.post('/getDetail', (request, response, next) => {

  const id = request.body.id;
  const numPerPage = request.body.pSize;
  const pageNum = request.body.pIndex;

  let query = `select id,name,title,group_desc,unit_code from table1
              where id = '${id}'`;

  let countQuery = `select count(*) total_item from 
                   (select id,name,title,group_desc,unit_code from table1
                    where id = '${id}') a`;

  const result = {};
  Promise.all([
    rows(),
    count()
  ])
  .then(results => {
    // results is an array and the first item is `rows`
    response.json(results[0]);
  })
  .catch(err => {
    // handle error
  });

  functionrows() {
    returnnewPromise((resolve, reject) => {
      pool.query(
        query,
        (err, data) => {
          if (err) {
            returnreject(err);
          }

          result.dataRows = data.rows;
          result.numPerPage = numPerPage;
          result.pageNum = pageNum;
          result.totalPage = Math.ceil(result.totalItem / numPerPage);
          result.firstItem = (pageNum - 1) * numPerPage + 1;
          result.lastItem = (pageNum * numPerPage > result.totalItem) ?
            result.totalItem : (pageNum * numPerPage);
          resolve(result);
        });
    });
  }

  functioncount() {
    returnnewPromise((resolve, reject) => {
      pool.query(
        countQuery,
        (err, data) => {
          if (err) {
            returnreject(err);
          }
          result.totalItem = parseInt(data.rows[0].total_item);
          result.totalPage = Math.ceil(result.totalItem / numPerPage);
          result.lastItem = (pageNum * numPerPage > result.totalItem) ?
            result.totalItem : (pageNum * numPerPage);
          resolve(result);
        });
    });
  }
});

The next example shows using async/await assuming pool.query can return a Promise. I'm also making the assumption that the object references will still be maintained and is why I'm assigning result.rows = results[0] in the try part of the try/catch.

router.post('/getDetail', async(request, response, next) => {

  const id = request.body.id;
  const numPerPage = request.body.pSize;
  const pageNum = request.body.pIndex;

  let query = `select id,name,title,group_desc,unit_code from table1
              where id = '${id}'`;

  let countQuery = `selectcount(*) total_item from 
                   (select id,name,title,group_desc,unit_code from table1
                    where id = '${id}') a`;

  const result = {};
  try {
    const results = await Promise.all([rows(), count()]);
    // results is an array and the first item is `rows`
    result.rows = results[0];
  } catch (err) {
    result.error = err.message;
  }
  response.json(result.rows);

  async function rows() {
    const data = await pool.query(query);
    result.dataRows = data.rows;
    result.numPerPage = numPerPage;
    result.pageNum = pageNum;
    result.totalPage = Math.ceil(result.totalItem / numPerPage);
    result.firstItem = (pageNum - 1) * numPerPage + 1;
    result.lastItem = (pageNum * numPerPage > result.totalItem)
      ? result.totalItem
      : (pageNum * numPerPage);
    return result;
  }

  async function count() {
    const data = await pool.query(countQuery);
    result.totalItem = parseInt(data.rows[0].total_item);
    result.totalPage = Math.ceil(result.totalItem / numPerPage);
    result.lastItem = (pageNum * numPerPage > result.totalItem)
      ? result.totalItem
      : (pageNum * numPerPage);
    return result;
  }
});

I hope this helps you understand how you can do parallel processing with async/await. The only issue I see that may come up in your code is if the rows query returns before the count query since totalItem won't be set yet.

EDIT: personally, I think I would handle the logic like this with 1 query instead of 2 different queries:

router.post('/getDetail', async(request, response, next) => {
  const id = request.body.id;
  const numPerPage = request.body.pSize;
  const pageNum = request.body.pIndex;

  let query = `select id,name,title,group_desc,unit_code from table1
              where id = '${id}'`;

  const result = {};
  try {
    const data = await pool.query(query);
    result.dataRows = data.rows;
    result.totalItem = data.rows.length; // data might already have a property for this
    result.numPerPage = numPerPage;
    result.pageNum = pageNum;
    result.totalPage = Math.ceil(result.totalItem / numPerPage);
    result.firstItem = (pageNum - 1) * numPerPage + 1;
    result.lastItem = (pageNum * numPerPage > result.totalItem)
      ? result.totalItem
      : (pageNum * numPerPage);
  } catch (err) {
    result.error = err.message;
  }

  response.json(result);
});

EDIT 2: After more discussion in the comments, I think this version will work better. It doesn't use the main result object to provide references and moves the "count" based properties to the count function to allow for parallel execution:

router.post('/getDetail', async(request, response, next) => {

  const id = request.body.id;
  const numPerPage = request.body.pSize;
  const pageNum = request.body.pIndex;

  let query = `select id,name,title,group_desc,unit_code from table1
              where id = '${id}'`;

  let countQuery = `selectcount(*) total_item from 
                   (select id,name,title,group_desc,unit_code from table1
                    where id = '${id}') a`;

  let result = { numPerPage, pageNum };
  try {
    const results = await Promise.all([rows(), count()]);
    // this will combine the properties from both results onto the `result` object
    result = Object.assign({}, result, ...results);
  } catch (err) {
    result.error = err.message;
  }
  response.json(result);

  async function rows() {
    const data = await pool.query(query);
    return { dataRows: data.rows };
  }

  async function count() {
    const data = await pool.query(countQuery);
    // redefining result here to be only used in this scopeconst result = {};
    result.totalItem = parseInt(data.rows[0].total_item);
    result.totalPage = Math.ceil(result.totalItem / numPerPage);
    result.firstItem = (pageNum - 1) * numPerPage + 1;
    result.lastItem = (pageNum * numPerPage > result.totalItem)
      ? result.totalItem
      : (pageNum * numPerPage);
    return result;
  }
});

Post a Comment for "Async.parallel To Async Await - Node.js"