什么是面向切面
初听面向切面编程时, 一头雾水, 什么是面向切面, 只听说过面向对象(OOP), 面向过程(PO), 函数式编程(FP), 面向切面 ? 面向的难道是某一个面?
面向搜索引擎后才了解到, 面向切面是一种编程范式(Aspect Oriented Programming), 简写 AOP, 特点是与原有逻辑解耦, 无侵入.
在后端开发工作中, 常见使用的场景是 断点调试/打印日志/...,
而在前端开发工作中, 应用场景比较灵活多变, 可以是在一次表单提交中, 在表单提交前作表单验证(前置), 或在表单提交后作数据刷新/页面跳转/Cookie 刷新等 (后置), 也可以在提交的同时作数据埋点(横向), 或是打印日志。。。
对于外部的新加入的逻辑, 为了不破坏原有的业务逻辑, 我们就可以使用 AOP 去组织代码, 分离 [业务逻辑] 与 [琐碎事务]
AOP 的关键概念点
- 前置(before) 在目标方法执行前执行
- 后置(after) 在目标方法执行后执行
- 异常(after throwing)在目标方法抛出异常时执行
- 环绕 (around) 在目标方法执行前后
前置执行函数
const before = function(fn, action) {
return function(...args) {
action.apply(this, args);
const res = fn.apply(this, args);
return { res, params: args };
};
};
后置执行函数
const after = function(fn, action) {
return function(...args) {
let res = fn.apply(this, args);
action.apply(this, args);
return { res, params: args };
};
};
异常执行函数
const throwing = function(fn, action) {
let ret = { res: undefined, params: undefined };
return function(...args) {
try {
const res = fn.apply(this, args);
return (ret = { res, params: args });
} catch (err) {
action.apply(this, args);
return (ret = { res: err, params: args });
}
};
};
环绕执行函数
const round = function(fn, actionBefore, actionAfter) {
return function(...args) {
actionBefore.apply(this, args);
const res = fn.apply(this, args);
actionAfter.apply(this, args);
return { res, params: args };
};
};
使用场景 -- 请求记录
const request = config => axios.request(config);
const ButtonClickFn = function () {
...do something
}
document.querySelector('#submit').click = before(ButtonClickFn, () => {
request({
url: 'http://your_upload_log_url',
method: 'GET',
params:
{ TYPE: 'BUTTON_CLICK', POSITION: '' }
});
});
使用场景 -- 异常处理
const originRequest = config => axios.request(config);
const wrapperedRequest = throwing(originRequest, function() {
...异常上报
});
其它实现方式
实际上除了使用高阶函数的方法实现, 我们还可以使用 ES7 的装饰器/Ojbect.defineProperty 实现, 或基于原型链去实现