AOP 模式在前端的应用

是什么?

AOP(Aspect-Oriented Programming)面向切片编程,是一种软件开发方法,旨在提高代码的模块化性和可维护性。它通过将横切关注点(cross-cutting concerns)从主要业务逻辑中分离出来,并以独立的方式处理这些关注点。

为什么?

在项目中代码不仅要实现业务需求还要完成各种与业务无关的的其他功能,比如日志埋点、异常上报。通过 AOP,开发者可以将这些关注点定义为"切面",然后在需要的地方将这些切面织入到应用程序的特定位置,而不必直接修改主要业务逻辑。

怎么做?

例子1:计算一个事件的执行时间

页面中有一个插入DOM 的事件。

js 复制代码
function appendEmpty() {
  for (let index = 0; index < 100; index++) {
    let div = document.createElement('div')
    document.body.appendChild(div)
  }
}

为了计算事件执行的时间,需要在方法内部插入计算时间的代码。

js 复制代码
function appendEmpty() {
  let start = new Date().getTime()
  for (let index = 0; index < 100; index++) {
    let div = document.createElement('div')
    document.body.appendChild(div)
  }
  let end = new Date().getTime()
  console.log(end - start)
}

代码问题

计算时间的逻辑全部插入到了源码中,不仅入侵源码,还改变了 appenEmpty 的业务职能, 如果再有其他的需求(埋点)会使函数越来越难维护。

解决方案

在全局的 Function 上挂载 before after 方法,用于在函数执行前和执行后执行。

js 复制代码
Function.prototype.before = function (beforeFn) {
  let self = this
  return function () {
    beforeFn.apply(this, arguments)
    return self.apply(this, arguments)
  }
}
 
Function.prototype.after = function (afterFn) {
  let self = this
  return function () {
    let ret = self.apply(this, arguments)
    afterFn.apply(this, arguments)
    return ret
  }
}

声明函数 fnTime 方法,内部调用 after 函数计算传入函数参数的执行时间。

js 复制代码
function appendEmpty() {
  for (let index = 0; index < 100; index++) {
    let div = document.createElement('div')
    document.body.appendChild(div)
  }
}

const fnTime = function (fn) {
  let start = new Date().getTime()
  return fn.after(function () {
    console.log(new Date().getTime() - start)
  })
}

fnTime(appendEmpty)()

例子 2: 表单提交

在表单提交时,通常会校验表单数据后进行表单提交

js 复制代码
function validate (value) {
  if (!value.length) {
    return false
  }
  if (value.length > 10) {
    return false
  }
  return true
}
 
function submit (value) {
  if (!validate(value)) return
  form.submit(value)
}
submit(formValue)

如果除了表单验证,还有操作日志上传、其他业务逻辑插入,就会导致 submit 的动作变的不那么 单纯, 可以使用 AOP 模式把提交无关的过程交给切片处理。

js 复制代码
let submit = function (value) {
  form.submit(value)
}
// 添加before 切面函数
submit.before(validate)(value)

实现切片方法

和上面的切片方法相比, 下面的切片方法多了 if(!ret) return false 的写法,这样可以在出错时阻断切片执行。

js 复制代码
// before 切片
Function.prototype.before = function (beforeFn) {
  let self = this
  return function () {
    let ret = beforeFn.apply(this, arguments)
    if(!ret) return false
    return self.apply(this, arguments)
  }
}

Function.prototype.after = function (afterFn) {
  let self = this
  return function () {
    let ret = self.apply(this, arguments)
    if(!ret) return false
    return afterFn.apply(this, arguments)
  }
}

例子 3:操作埋点

在点击 btnClick 后打开弹出框,并上传埋点日志。

js 复制代码
methods: {
   track () {
     // 添加埋点
     this.$tracker({ elementCode: 104340 })
   },
   showDialog () {
     // 业务逻辑。。。
     this.showDialog = true
   },
   btnClick () {
    // 业务逻辑。。。。。
     this.showDialog.after(this.track)()
   }
 }

使用装饰器设计 AOP

除了使用传入函数参数的方式,装饰器用来实现切片写法上会优雅些许

js 复制代码
function log(target, name, descriptor) {
    var oldValue = descriptor.value;
 
    descriptor.value = function () {
        console.log(`Calling "${name}" with`, arguments);
        return oldValue.apply(null, arguments);
    }
    return descriptor;
}
 
 
// 日志应用
class Maths {
    @log
    add(a, b) {
        return a + b;
    }
}
const math = new Maths();
// passed parameters should get logged now
math.add(2, 4);

总结

AOP 的业务应用模式不难理解,相比于 IoC 有更多的业务应用场景。 在 NestJs 框架中,中间件,拦截器,守卫,异常过滤器,管道也都是基于 AOP 设计。

AOP 应用架构

相关推荐
张西餐14 小时前
Promise的理解
前端
天渺工作室14 小时前
别再写改名脚本了,一个 Vite 插件搞定压缩、校验、自动哈希命名vite-plugin-pack-orchestrator
前端·vite
大龄程序员狗哥14 小时前
第30篇:使用Flask部署你的第一个AI模型——打造简易Web API(项目实战)
前端·人工智能·flask
AI砖家15 小时前
解剖 Claude Code:如何搭建一个企业级的私有化 AI 编程助手
前端·人工智能·ai编程
用户57573033462415 小时前
拒绝“首屏爆炸”:用 React 哨兵模式与懒加载打造丝滑列表
前端
大腕先生16 小时前
通用分页超详细介绍(附带源代码解析&页面展示效果)
xml·java·linux·服务器·开发语言·前端·idea
睿智的海鸥16 小时前
Markdown 语法大全详解
开发语言·前端·javascript·css·html
Highcharts.js16 小时前
用Highcharts如何动态向一个序列添加点
前端·javascript·react.js·highcharts
HookJames16 小时前
设计Section 09 · Cost & Lead Time Factors 的完整 Block Editor 操作步骤
前端
玖玖passion16 小时前
React 常用 Hooks 函数及使用方法完全指南(useState / useEffect / useRef / useContext / useCallback / useMemo / useReducer)
前端·javascript