阅读 211

微信小程序云函数封装(二)

前言

前几天对微信小程序云函数封装了路由分发,对微信小程序封装了 ServiceUtil ,今天我们来封装一下 job ,并升级一下 ServiceUtil ,源码在文章底部

上一篇: 封装微信小程序云函数(一)

云函数封装

首先看一下新的目录结构

image1.png

其中 controllermodel 跟上次介绍的没有变,所以这里就不介绍了,这里主要介绍一下 LeJob 的封装

封装 LeJob

首先我们来看 index 文件, index 文件主要定义了 LeRouterLeJob

cloudfunctions\job\common\index.js

const LeBase = require('./LeBase')
const { checkRequestParams, getJobs } = require('./util/index')
class LeRouter extends LeBase {
  constructor(options) {
    super(options);
    this.routers = options.routers || {};
  }
  run() {
    return async (event, context) => {
      const router = this.routers[event.$url];
      // 若 router 没有找到则抛出 router not found
      if (!router) {
        throw Error('router not found')
      }
      // 引入 controller
      const Controller = require(this.routers[event.$url]);
      // 检查字段
      checkRequestParams(event, Controller.rules);
      // 执行 controller 中的 main()
      return await Controller.main.call(this, event, context);
    }
  }
}
class LeJob extends LeBase {
  constructor(options) {
    super(options);
    this.jobs = options.jobs || {};
  }
  run() {
    return async (event, context) => {
      // 获取应该执行的 job
      const jobNames = getJobs(this, this.config.triggers);
      if (jobNames) {
        jobNames.forEach((jobName) => {
          // 依次导入 job 并执行
          const Controller = require(jobName);
          Controller.main.call(this, event, context);
        })
      }
    }
  }
}
module.exports = { LeRouter, LeJob }
复制代码

LeRouterLeJob 是继承自 LeBase ,我们看一下 LeBase

LeBase 主要是给实例化的对象封装 _cloudconfigDB 属性

// 初始化对象属性
function initAttr(options) {
  this._cloud = require('wx-server-sdk');
  this.config = options.config || {};
  setDB.call(this);
}
// 初始化 DB 
function setDB() {
  Object.defineProperty(this, 'DB', {
    configurable: false,
    get() {
      this._DB || (this._DB = require('./DB')(this));
      return this._DB;
    }
  })
}
// 初始化 cloud
function initCloud() {
  this._cloud.init({
    env: this.config.env,
  });
}
class LeBase {
  constructor(options) {
    initAttr.call(this, options);
    initCloud.call(this);
  }
}
module.exports = LeBase
复制代码

DB 文件与上次没有任何区别,在这里贴出看一下吧

cloudfunctions\router\common\DB.js

// 根据配置的 env 和 throwOnNotFound 初始化 database对象
function initDB(leOptions) {
  const config = leOptions.config
  return leOptions._cloud.database({
    env: config && config.env,
    throwOnNotFound: config && config.DBThrowOnNotFound,
  });
}
module.exports = initDB
复制代码

我们看一下我们前面 index 文件用到的方法

cloudfunctions\router\common\util\index.js

  ...
  ...

function getJobs(LeJob, triggers) {
  // 因为配置 job 使用 cron 语句,所以引入 cron-parser 来解析
  const cronParse = require('cron-parser') 
  const { jobs } = LeJob;
  const time = new Date().getTime() - 1;
  return Object.keys(jobs).reduce((jobNames, key) => {
    const intervalTime = cronParse.parseExpression(key).prev().getTime();
    const job = jobs[key];
    if (time - intervalTime <= triggers) {
      // job 可以配置为字符串或对象
      if (typeof job === 'string') {
        jobNames.push(jobs[key]);
      } else if (typeof job === 'object') {
        jobNames.push(...jobs[key]);
      }
    }
    return jobNames;
  }, []);
}
module.exports= { checkRequestParams, getJobs }
复制代码

使用

那我们看一下我们云函数的 index 文件吧

cloudfunctions\job\index.js

const { LeJob } = require('./common/index')
const options = {
  // 这里可以配置一些使用到的配置项
  config: {
    // 本云函数名
    name: 'router',
    // 这里单位为毫秒,需要与 config.json 文件中的 triggers 配置相同
    triggers: 60 * 60 * 5 * 1000,
  },
  // 这里以 cron 格式的字符串为键,以 controller 的路径为值,值可以是数组或字符串
  jobs: {
    "0 0 17 * * 6": ["controller/hello/HelloWorld"],
  },
}
const app = new LeJob(options)
exports.main = app.run()
复制代码

然后我们看一下 config.json 文件

这里就是配置一下 triggers 配置项, triggers 现在必须配置为间隔一定时间执行,如 5 个小时

cloudfunctions\job\config.json

{
  "triggers": [
    {
      "name": "job",
      "type": "timer",
      "config": "* * */5 * * * *"
    }
  ]
}
复制代码

controller 文件和 model 文件这里就不介绍了,跟之前的写法一样

小程序封装 ServiceUtil

先看一下目录

image2.png

这个封装改动很小,就改动了一处

使用 ServiceUtil 时需要先实例化 ServiceUtil ,可以传入云函数名,以支持云函数分模块开发

miniprogram\engine\util\ServiceUtil.js

export default class ServiceUtil {
  constructor(cloudName = CLOUD_NAME) {
    this.cloudName = cloudName;
  }

  request = (url, data = {}, complete = (res) => {}) => {
    ...
    ...
  }
  
  callFunction = (url, data = {}, success = () => {}, fail = () => {}, complete = (res) => {}) => {
    ...
    ...
  }
} 
复制代码

所以我们使用的时候需要先实例化 ServiceUtil

miniprogram\engine\User.js

import ServiceUtil from './util/ServiceUtil.js'
const serviceUtil = new ServiceUtil('router')
export default class User {
  static getById = async (id) => {
    return await serviceUtil.request('user.GetById', { id });
  }
}
复制代码

image2.png

运行一下

image3.png

总结

这里的封装还非常的简陋,各位大佬多多指教

源码地址

文章分类
前端
文章标签