Bootstrap

JavaScript系列(15)-- AOP编程

JavaScript AOP编程 🎯

今天,让我们深入了解JavaScript中的AOP(面向切面编程)。AOP是一种强大的编程范式,它能帮助我们更好地处理横切关注点,提高代码的模块化程度。

AOP基础概念 🌟

💡 小知识:AOP(Aspect-Oriented Programming)是一种通过分离横切关注点来增加程序的模块化的编程范式。横切关注点是指那些影响多个类或模块的功能,如日志记录、性能统计、安全控制等。

AOP的核心概念 📊

// 1. 切面(Aspect)
class Aspect {
    // 前置通知
    before(target, methodName, advice) {
        const original = target[methodName];
        target[methodName] = function(...args) {
            advice.apply(this, args);
            return original.apply(this, args);
        };
    }
    
    // 后置通知
    after(target, methodName, advice) {
        const original = target[methodName];
        target[methodName] = function(...args) {
            const result = original.apply(this, args);
            advice.call(this, result);
            return result;
        };
    }
    
    // 环绕通知
    around(target, methodName, advice) {
        const original = target[methodName];
        target[methodName] = function(...args) {
            return advice.call(this, {
                target: this,
                method: original,
                args: args
            });
        };
    }
    
    // 异常通知
    afterThrowing(target, methodName, advice) {
        const original = target[methodName];
        target[methodName] = function(...args) {
            try {
                return original.apply(this, args);
            } catch (error) {
                advice.call(this, error);
                throw error;
            }
        };
    }
    
    // 最终通知
    afterFinally(target, methodName, advice) {
        const original = target[methodName];
        target[methodName] = function(...args) {
            try {
                return original.apply(this, args);
            } finally {
                advice.call(this);
            }
        };
    }
}

// 2. 切点(Pointcut)
class Pointcut {
    constructor(pattern) {
        this.pattern = pattern;
    }
    
    // 方法匹配
    matchMethod(methodName) {
        if (typeof this.pattern === 'string') {
            return methodName === this.pattern;
        }
        if (this.pattern instanceof RegExp) {
            return this.pattern.test(methodName);
        }
        return false;
    }
    
    // 类匹配
    matchClass(target) {
        return target.constructor.name.match(this.pattern);
    }
}

// 3. 通知(Advice)
class Advice {
    // 创建日志通知
    static createLoggingAdvice() {
        return {
            before: (target, method, args) => {
                console.log(`Calling ${method} with args:`, args);
            },
            after: (result) => {
                console.log('Method returned:', result);
            },
            error: (error) => {
                console.error('Method threw error:', error);
            }
        };
    }
    
    // 创建性能监控通知
    static createPerformanceAdvice() {
        return {
            before: () => {
                this.startTime = performance.now();
            },
            after: (result) => {
                const endTime = performance.now();
                console.log(`Method took ${endTime - this.startTime}ms`);
                return result;
            }
        };
    }
}

AOP实现方式 🔧

// 1. 装饰器实现
function aopDecorators() {
    // 日志装饰器
    function log(target, key, descriptor) {
        const original = descriptor.value;
        descriptor.value = function(...args) {
            console.log(`Calling ${key} with args:`, args);
            const result = original.apply(this, args);
            console.log(`${key} returned:`, result);
            return result;
        };
        return descriptor;
    }
    
    // 性能监控装饰器
    function measure(target, key, descriptor) {
        const original = descriptor.value;
        descriptor.value = function(...args) {
            const start = performance.now();
            const result = original.apply(this, args);
            const end = performance.now();
            console.log(`${key} took ${end - start}ms`);
            return result;
        };
        return descriptor;
    }
    
    // 重试装饰器
    function retry(times = 3, delay = 1000) {
        return function(target, key, descriptor) {
            const original = descriptor.value;
            descriptor.value = async function(...args) {
                for (let i = 0; i < times; i++) {
                    try {
                        return await original.apply(this, args);
                    } catch (error) {
                        if (i === times - 1) throw error;
                        await new Promise(resolve => 
                            setTimeout(resolve, delay)
                        );
                        console.log(`Retrying ${key} (${i + 1}/${times})`);
                    }
                }
            };
            return descriptor;
        };
    }
}

// 2. 代理实现
class AopProxy {
    static create(target, advice) {
        return new Proxy(target, {
            get(target, property) {
                const value = target[property];
                if (typeof value !== 'function') return value;
                
                return function(...args) {
                    if (advice.before) {
                        advice.before(target, property, args);
                    }
                    
                    let result;
                    try {
                        result = value.apply(target, args);
                        if (advice.after) {
                            advice.after(result);
                        }
                    } catch (error) {
                        if (advice.error) {
                            advice.error(error);
                        }
                        throw error;
                    }
                    
                    return result;
                };
            }
        });
    }
}

// 3. 中间件实现
class AopMiddleware {
    constructor() {
        this.middlewares = [];
    }
    
    use(middleware) {
        this.middlewares.push(middleware);
        return this;
    }
    
    execute(target, methodName, args) {
        const stack = this.middlewares.map(middleware => ({
            before: middleware.before?.bind(middleware),
            after: middleware.after?.bind(middleware),
            error: middleware.error?.bind(middleware)
        }));
        
        const executeStack = async (index = 0) => {
            if (index >= stack.length) {
                return target[methodName].apply(target, args);
            }
            
            const middleware = stack[index];
            
            try {
                if (middleware.before) {
                    await middleware.before(target, methodName, args);
                }
                
                const result = await executeStack(index + 1);
                
                if (middleware.after) {
                    await middleware.after(result);
                }
                
                return result;
            } catch (error) {
                if (middleware.error) {
                    await middleware.error(error);
                }
                throw error;
            }
        };
        
        return executeStack();
    }
}

AOP实际应用 💼

让我们看看AOP在实际开发中的一些应用场景:

// 1. 日志系统
class LoggingSystem {
    static createLogger() {
        return {
            before(target, method, args) {
                console.log(`[${new Date().toISOString()}] Calling ${
                    target.constructor.name
                }.${method}`);
                console.log('Arguments:', args);
            },
            
            after(result) {
                console.log('Result:', result);
            },
            
            error(error) {
                console.error('Error:', error);
                // 可以添加错误上报逻辑
            }
        };
    }
    
    static applyLogging(target, methods) {
        const logger = this.createLogger();
        const aspect = new Aspect();
        
        methods.forEach(method => {
            aspect.before(target, method, logger.before);
            aspect.after(target, method, logger.after);
            aspect.afterThrowing(target, method, logger.error);
        });
    }
}

// 2. 性能监控
class PerformanceMonitor {
    constructor() {
        this.metrics = new Map();
    }
    
    createAdvice(metricName) {
        return {
            before: () => {
                this.startTime = performance.now();
            },
            
            after: (result) => {
                const duration = performance.now() - this.startTime;
                if (!this.metrics.has(metricName)) {
                    this.metrics.set(metricName, []);
                }
                this.metrics.get(metricName).push(duration);
                return result;
            }
        };
    }
    
    getMetrics(metricName) {
        const measurements = this.metrics.get(metricName) || [];
        if (measurements.length === 0) return null;
        
        return {
            average: measurements.reduce((a, b) => a + b, 0) / measurements.length,
            min: Math.min(...measurements),
            max: Math.max(...measurements),
            count: measurements.length
        };
    }
}

// 3. 缓存系统
class CacheAspect {
    constructor() {
        this.cache = new Map();
    }
    
    createAdvice(options = {}) {
        const { ttl = 60000, keyGenerator = (...args) => JSON.stringify(args) } = options;
        
        return {
            before: (target, method, args) => {
                const key = `${target.constructor.name}.${method}:${
                    keyGenerator(...args)
                }`;
                
                if (this.cache.has(key)) {
                    const { value, timestamp } = this.cache.get(key);
                    if (Date.now() - timestamp < ttl) {
                        return { cached: true, value };
                    }
                    this.cache.delete(key);
                }
                return { cached: false, key };
            },
            
            after: (result, context) => {
                if (!context.cached) {
                    this.cache.set(context.key, {
                        value: result,
                        timestamp: Date.now()
                    });
                }
                return context.cached ? context.value : result;
            }
        };
    }
}

性能优化 ⚡

AOP实现中的性能优化技巧:

// 1. 切面优化
class OptimizedAspect {
    // 使用WeakMap存储原始方法
    #originalMethods = new WeakMap();
    
    // 优化的方法包装
    wrapMethod(target, methodName, advice) {
        if (!this.#originalMethods.has(target)) {
            this.#originalMethods.set(target, new Map());
        }
        
        const methodMap = this.#originalMethods.get(target);
        if (!methodMap.has(methodName)) {
            methodMap.set(methodName, target[methodName]);
        }
        
        const original = methodMap.get(methodName);
        return function(...args) {
            return advice.call(this, {
                target: this,
                method: original,
                args: args
            });
        };
    }
    
    // 恢复原始方法
    unwrapMethod(target, methodName) {
        const methodMap = this.#originalMethods.get(target);
        if (methodMap && methodMap.has(methodName)) {
            target[methodName] = methodMap.get(methodName);
            methodMap.delete(methodName);
        }
    }
}

// 2. 缓存优化
class CacheOptimizer {
    static createCachedAspect(options = {}) {
        const {
            maxSize = 1000,
            ttl = 60000,
            keyGenerator = (...args) => JSON.stringify(args)
        } = options;
        
        const cache = new Map();
        const timestamps = new Map();
        
        return {
            before(target, method, args) {
                const key = keyGenerator(target, method, args);
                const now = Date.now();
                
                // 清理过期缓存
                if (timestamps.has(key)) {
                    const timestamp = timestamps.get(key);
                    if (now - timestamp > ttl) {
                        cache.delete(key);
                        timestamps.delete(key);
                    }
                }
                
                // 缓存命中
                if (cache.has(key)) {
                    return { cached: true, value: cache.get(key) };
                }
                
                // 缓存大小控制
                if (cache.size >= maxSize) {
                    const oldestKey = timestamps.keys().next().value;
                    cache.delete(oldestKey);
                    timestamps.delete(oldestKey);
                }
                
                return { cached: false, key };
            },
            
            after(result, context) {
                if (!context.cached) {
                    cache.set(context.key, result);
                    timestamps.set(context.key, Date.now());
                }
                return context.cached ? context.value : result;
            }
        };
    }
}

// 3. 执行优化
class ExecutionOptimizer {
    // 批量处理优化
    static batchProcess(aspect, batchSize = 100) {
        const queue = [];
        let processing = false;
        
        return {
            async before(target, method, args) {
                queue.push({ target, method, args });
                
                if (queue.length >= batchSize && !processing) {
                    processing = true;
                    await this.processBatch();
                    processing = false;
                }
            },
            
            async processBatch() {
                const batch = queue.splice(0, batchSize);
                return Promise.all(
                    batch.map(({ target, method, args }) =>
                        aspect.execute(target, method, args)
                    )
                );
            }
        };
    }
}

最佳实践建议 💡

  1. AOP使用场景
// 1. 横切关注点处理
function crossCuttingConcerns() {
    // 认证切面
    const authAspect = {
        before(target, method, args) {
            if (!isAuthenticated()) {
                throw new Error('未认证');
            }
        }
    };
    
    // 权限切面
    const authorizationAspect = {
        before(target, method, args) {
            if (!hasPermission(method)) {
                throw new Error('无权限');
            }
        }
    };
    
    // 事务切面
    const transactionAspect = {
        async around(joinPoint) {
            const transaction = await beginTransaction();
            try {
                const result = await joinPoint.method.apply(
                    joinPoint.target, 
                    joinPoint.args
                );
                await transaction.commit();
                return result;
            } catch (error) {
                await transaction.rollback();
                throw error;
            }
        }
    };
}

// 2. 代码复用
function codeReuse() {
    // 重试机制
    const retryAspect = {
        async around(joinPoint) {
            const maxRetries = 3;
            let lastError;
            
            for (let i = 0; i < maxRetries; i++) {
                try {
                    return await joinPoint.method.apply(
                        joinPoint.target, 
                        joinPoint.args
                    );
                } catch (error) {
                    lastError = error;
                    if (i < maxRetries - 1) {
                        await new Promise(resolve => 
                            setTimeout(resolve, 1000 * Math.pow(2, i))
                        );
                    }
                }
            }
            
            throw lastError;
        }
    };
    
    // 缓存机制
    const cacheAspect = {
        before(target, method, args) {
            const key = `${target.constructor.name}.${method}:${
                JSON.stringify(args)
            }`;
            const cached = cache.get(key);
            if (cached) return { cached: true, value: cached };
            return { cached: false, key };
        },
        
        after(result, context) {
            if (!context.cached) {
                cache.set(context.key, result);
            }
            return context.cached ? context.value : result;
        }
    };
}

// 3. 调试和监控
function debuggingAndMonitoring() {
    // 调试切面
    const debugAspect = {
        before(target, method, args) {
            console.log(`[DEBUG] Entering ${method}`);
            console.log('Arguments:', args);
        },
        
        after(result) {
            console.log('Result:', result);
            console.log('[DEBUG] Exiting method');
        },
        
        error(error) {
            console.error('[DEBUG] Error:', error);
        }
    };
    
    // 监控切面
    const monitoringAspect = {
        before() {
            this.startTime = performance.now();
        },
        
        after(result) {
            const duration = performance.now() - this.startTime;
            metrics.record('method.duration', duration);
            return result;
        },
        
        error(error) {
            metrics.increment('method.errors');
            throw error;
        }
    };
}

结语 📝

AOP是一种强大的编程范式,它能帮助我们更好地组织和管理代码。我们学习了:

  1. AOP的核心概念和实现方式
  2. 不同类型的切面和通知
  3. 实际应用场景
  4. 性能优化技巧
  5. 最佳实践和注意事项

💡 学习建议:在使用AOP时,要注意平衡其带来的好处和复杂性。过度使用AOP可能会使代码难以理解和调试。建议从简单的日志、性能监控等场景开始,逐步扩展到更复杂的应用。


如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

;