async库在mongoose中的应用

2020年04月18日

async库是npm上的一个处理异步操作的超级库,可以实现很多异步操作和流程控制。虽然一些简单的异步控制我们可以使用Promise或者async/await语法来实现,但是遇到异步流程较多的情况我们将难以处理。

本文主要介绍async在node环境中配合mongoose实现数据库分页和async配合mongoose查询查询连续n天的每天数据。

安装async

npm i async

官方文档

asyn的两个api介绍

parallel(tasks, callback) 并行

并行运行功能的任务集合,而无需等待上一个功能完成。 如果任何一个函数将错误传递给其回调,则立即使用错误的值调用主回调。 任务完成后,结果将作为数组或者对象传递到最终回调。

example:

async.parallel({
    one: function(callback) {
        setTimeout(function() {
            callback(null, 1);
        }, 200);
    },
    two: function(callback) {
        setTimeout(function() {
            callback(null, 2);
        }, 100);
    }
}, function(err, results) {
    // results is now equals to: {one: 1, two: 2}
});

series(tasks, callback) 串行

依次运行任务集合中的功能,每一个都在上一个功能完成后运行。 如果系列中的任何函数将错误传递给其回调,则不会再运行任何函数,并且会立即使用错误的值调用回调。 否则,当任务完成时,回调将收到结果数组。
也可以使用对象而不是数组。 每个属性都将作为函数运行,并且结果将作为对象而不是数组传递到最终回调。 这是处理async.series结果的一种更易读的方法。

example:

async.series({
    one: function(callback) {
        setTimeout(function() {
            callback(null, 1);
        }, 200);
    },
    two: function(callback){
        setTimeout(function() {
            callback(null, 2);
        }, 100);
    }
}, function(err, results) {
    // results is now equal to: {one: 1, two: 2}
});

知道上面的两个关键api我们就可以来完成一些函数的应用了。

分页

const mongoose = require('mongoose')
const async = require('async')
/**分页
 * page, pageSize, Model, populate = '', queryParams = {}, sortParams
 * @param {*} options
 */
exports.queryPagination = (options = {}, callback) => {
  let {
    page,
    pageSize,
    Model,
    populate = '',
    queryParams = {},
    sortParams,
    field = ''
  } = options
  let start = (page - 1) * pageSize
  let $page = {
    pageNumber: page
  }

  async.parallel(
    {
      count: function(cb) {
        Model.countDocuments(queryParams).exec(cb)
      },
      data: function(cb) {
        Model.find(queryParams)
          .skip(start)
          .limit(pageSize)
          .populate(populate)
          .sort(sortParams)
          .select(field)
          .exec(cb)
      }
    },
    function(err, results) {
      let count = results.count
      $page.count = count
      $page.pageTotal = Math.ceil(count / pageSize)
      $page.data = results.data
      callback(err, $page)
    }
  )
}

查询连续n天的每天数据

以查询最近7天都访问趋势为例

/**
 * 7天访问趋势
 */
exports.dayViewsController = (req, res) => {
  // 获取最近7天的日期
  const days = get7day()
  // async.series的对象参数
  const parallelQuerys = {}

  days.forEach((day) => {
    let startDate = new Date(day).getTime()
    let lastDate = new Date(
      moment(startDate).add(1, 'days').format('YYYY-MM-DD')
    ).getTime()

    parallelQuerys[String(day)] = function (cb) {
      Vistor.countDocuments({
        browse_time_stamp: {
          $gte: startDate,
          $lt: lastDate,
        },
      }).exec(cb)
    }
  })

  async.series(parallelQuerys, function (err, results) {
    if (err) {
      responseError({ err, res })
    } else {
      responseSuccess({ res, data: results })
    }
  })
}

总结:

对于异步编程模型来说,在同步编程中很容易做到的事情,现在却变得很麻烦,async的流程控制大大简化了很多复杂的操作,使用async库来编写数据库的查询流程也变得及其简单。

0 条评论