async.parallel 到异步等待 - Node.js

async.parallel to async await - Node.js

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

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 对象来传递引用。

在下面的代码中,我没有使用 async/await 因为对于这个例子来说这不是完全必要的,因为 pool.query 方法需要一个回调。相反,我创建了 rowscount 函数 return Promises。然后我使用带有 Promise.all 的那些,这将使两个承诺 运行 并行,并且 return 结果作为数组按照承诺传递给 Promise.all 的相同顺序。当 pool.query return 是一个承诺时,请参阅使用 async/await 的示例。

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 可以 return Promise。我还假设对象引用仍将被维护,这就是为什么我在 try/catch.

try 部分分配 result.rows = results[0]
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 进行并行处理。我看到您的代码中可能出现的唯一问题是 rows 查询 return 是否在 count 查询之前,因为 totalItem 尚未设置。

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

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

编辑 2:在评论中进行更多讨论后,我认为这个版本会更好用。它不使用主 result 对象来提供引用,而是将基于 "count" 的属性移动到 count 函数以允许并行执行:

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