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 应用架构

相关推荐
dwedwswd4 分钟前
技术速递|从 0 到 1:用 Playwright MCP 搭配 GitHub Copilot 搭建 Web 应用调试环境
前端·github·copilot
2501_9387742918 分钟前
Leaflet 弹出窗实现:Spring Boot 传递省级旅游口号信息的前端展示逻辑
前端·spring boot·旅游
meichaoWen33 分钟前
【CSS】CSS 面试知多少
前端·css
我血条子呢39 分钟前
【预览PDF】前端预览pdf
前端·pdf·状态模式
90后的晨仔1 小时前
报错 找不到“node”的类型定义文件。 程序包含该文件是因为: 在 compilerOptions 中指定的类型库 "node" 的入口点 。
前端
90后的晨仔1 小时前
5分钟搭建你的第一个TypeScript项目
前端·typescript
专注前端30年1 小时前
Vue2 中 v-if 与 v-show 深度对比及实战指南
开发语言·前端·vue
90后的晨仔1 小时前
TypeScript是什么?为什么前端必须学它?
前端
用户47949283569152 小时前
从 58MB 到 2.6MB:我是如何将 React 官网性能提升 95% 的
前端·javascript
该用户已不存在2 小时前
7个让全栈开发效率起飞的 Bun 工作流
前端·javascript·后端