async.parallel到async await-Node.js [英] async.parallel to async await - Node.js

查看:68
本文介绍了async.parallel到async await-Node.js的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用express-promise-router在来自node.js的查询调用中实现异步/等待.有时,当我需要获取表的数据时,我使用async.parallel来获取数据以及作为单独数据的计数并将其合并.我在这里使用回调.我该如何继续使用async/await?

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 well as the count as separate data and merge them. I am using callbacks here. How do I go ahead using async/await for these?

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 = {};

  async.parallel({
    rows: (cb) => {
      pool.query(
        query,
        (err, data) => {
          if (!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)
          }
          cb(err, result)
        })
    },
    count: (cb) => pool.query(
      countQuery,
      (err, data) => {
        if (!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)
        }
        cb(err, result);
      })
  }, (err, result) => {
    if (err) {
      result.error = err.message;
    }
    response.json(result.rows)
  })
});

推荐答案

我试图使代码与上面的代码相似,但是最后我注意到您正在使用更高级别的result对象来传递周围的参考.

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.

在下面的代码中,我没有使用async/await,因为对于本示例来说,这并不是完全必要的,因为pool.query方法采用了回调.相反,我创建了rowscount函数,它们返回Promises.然后,将它们与Promise.all一起使用,这将使两个promise并行运行,并以将promise传递给Promise.all的相同顺序将结果作为数组返回.进一步请参见使用async/await代替pool.query返回promise的示例.

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

  function rows() {
    return new Promise((resolve, reject) => {
      pool.query(
        query,
        (err, data) => {
          if (err) {
            return reject(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);
        });
    });
  }

  function count() {
    return new Promise((resolve, reject) => {
      pool.query(
        countQuery,
        (err, data) => {
          if (err) {
            return reject(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);
        });
    });
  }
});

下一个示例显示使用async/await并假定pool.query可以返回Promise.我还假设仍将保留对象引用,这就是为什么要在try/catchtry部分中分配result.rows = results[0]的原因.

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 = `select count(*) 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;
  }
});

我希望这可以帮助您了解如何使用async/await进行并行处理.我认为您的代码中可能会出现的唯一问题是,由于尚未设置totalItem,因此rows查询是否在count查询之前返回.

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.

就我个人而言,我认为我将使用1个查询而不是2个不同的查询来处理这样的逻辑:

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

在评论中进行了更多讨论之后,我认为此版本会更好.它不使用主result对象提供引用,也不将基于计数"的属性移动到count函数以允许并行执行:

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 = `select count(*) 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 scope
    const 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;
  }
});

这篇关于async.parallel到async await-Node.js的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆