nodejs旧项目不能使用装饰器如何AOP?

文章介绍了如何在不支持装饰器的Node.js旧系统中,通过自定义的AOP(面向切面编程)方法来实现函数运行时间的日志记录,从而定位性能瓶颈。首先定义了一个aop.inject函数来注入装饰器,然后创建了一个计时装饰器testAOP,最后展示了如何批量对类的所有方法应用这个装饰器,以实现全类的性能监控。
摘要由CSDN通过智能技术生成

最近多年前的一个nodejs旧系统,有效能问题,需要对该系统的一些Function添加运行时间的log来判断是哪个Step耗时较多以作针对性优化。
实现该需求当然首选是AOP了,使用装饰器来实现AOP是简单不过的事情,但旧系统根本没有装Babel,不支持装饰器,只能自己动手实现AOP了。
首先添加aop inject function:

// aop.js file
const inject = (decorator, target, methodName) => {
   const method = target[methodName];
   const descriptor = { ...method, value: method };
   decorator(target, methodName, descriptor);
   Object.defineProperty(target, methodName, descriptor);
};

module.exports = { inject };

接着添加计时的逻辑代码(与使用装饰器时的代码一致):

// aopBussness.js file
const NS_PER_SEC = 1e9;
const MS_PER_SEC = 1e6;
const testAOP = function (target, methodName, descriptor) {
	const method = descriptor.value;
    descriptor.value = function (...args) {
      const begin = process.hrtime();    
      let result;
      try {
        console.info(`befor run, ${Object(target).name}.${methodName} input is:`, JSON.stringify(args));
        result = descriptor.apply(this, args);
        return result;
      } catch (err) {
        console.error('error:', err);
        throw err;
      } finally {        
        const end = process.hrtime(begin);
        const durationMs = (end[0] * NS_PER_SEC + end[1]) / MS_PER_SEC;
        console.info(`${Object(target).name}.${methodName} Done. durationMs:${durationMs} `);
      }
    };
};
module.exports = { testAOP };

最后,将计时代码注入原逻辑代码:

// orgSC.js file
const aop = require('./aop');
const { testAOP } = require('./aopBussness');
// 原代码:
// const tools = {
//   fun1(v, s) {
//     // ...
//   },
// 
//   fun2(t) {
//    // ...
//   },
// };
// 改为Class:
class Tools {
  static fun1(v,s) {
  	 // ...
  }
  static fun2(t) {
    // ...
  }
}
aop.inject(testAOP, Tools, 'fun1'); // 注入
aop.inject(testAOP, Tools, 'fun2'); // 注入
// module.exports = tools;
module.exports = Tools;

这样就可以对tools的fun1和fun2函数添加上耗时计算的逻辑了。

但如果对一个Class的所有Function都需要注入,这样一个个的写就太麻烦了,于是aop.js 可优化为:

// aop.js file
const getMethods = (obj) =>
  Object.getOwnPropertyNames(Object.getPrototypeOf(obj)).filter(
    (item) => typeof obj[item] === 'function'
  );
  
const inject = (decorator, module, methodName = null) => {
  const target = module;
  if (typeof methodName === 'undefined' || methodName === null) {
    const methods = getMethods(module);
    methods.forEach((m) => {
      inject(decorator, target, m);
    });
  } else {
    const method = target[methodName];
    const descriptor = { ...method, value: method };
    decorator(target, methodName, descriptor);
    Object.defineProperty(target, methodName, descriptor);
  }
};

module.exports = { inject };

而注入时只需要:aop.inject(testAOP,Tools);就可以针对该Tools Class 全部Funtion注入了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值