MST

星途 面试题库

面试题:TypeScript装饰器与依赖注入在大型项目架构中的应用优化

在一个具有多个模块和复杂依赖关系的大型TypeScript项目中,使用装饰器和依赖注入来管理依赖。请阐述如何优化依赖注入的性能,例如避免循环依赖,以及如何利用装饰器实现切面编程(AOP)来处理如日志记录、权限验证等横切关注点,给出具体的实现思路和关键代码示例。
44.9万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

优化依赖注入性能

  1. 避免循环依赖
    • 思路
      • 在依赖注入容器中,维护一个记录正在解析的依赖的栈。当解析一个新的依赖时,将其添加到栈中。如果在解析过程中发现当前依赖已经在栈中,就说明存在循环依赖。
      • 采用深度优先搜索(DFS)的方式解析依赖。从顶层依赖开始,递归地解析其所有依赖,在这个过程中检查循环。
    • 关键代码示例(简化示意)
class DependencyContainer {
    private resolvingStack: string[] = [];
    private dependencies: { [key: string]: () => any } = {};

    register(key: string, factory: () => any) {
        this.dependencies[key] = factory;
    }

    resolve(key: string): any {
        if (this.resolvingStack.includes(key)) {
            throw new Error(`Circular dependency detected for ${key}`);
        }
        this.resolvingStack.push(key);
        const factory = this.dependencies[key];
        if (!factory) {
            throw new Error(`Dependency ${key} not registered`);
        }
        const result = factory();
        this.resolvingStack.pop();
        return result;
    }
}
  1. 其他性能优化
    • 延迟加载
      • 思路:只有在真正需要某个依赖时才进行实例化。可以通过使用工厂函数来实现,在resolve方法中调用工厂函数来创建实例,而不是在注册依赖时就创建。
      • 关键代码示例
class DependencyContainer {
    //... 其他代码
    resolve(key: string): any {
        const factory = this.dependencies[key];
        if (!factory) {
            throw new Error(`Dependency ${key} not registered`);
        }
        return factory();
    }
}
// 注册依赖
container.register('service', () => new Service());

利用装饰器实现切面编程(AOP)

  1. 日志记录
    • 思路:创建一个日志装饰器,该装饰器在目标方法执行前后记录日志信息。可以通过反射获取方法的名称等信息,然后使用console.log或日志库记录日志。
    • 关键代码示例
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
        console.log(`Calling method ${propertyKey} with args:`, args);
        const result = originalMethod.apply(this, args);
        console.log(`Method ${propertyKey} returned:`, result);
        return result;
    };
    return descriptor;
}

class MyService {
    @log
    public myMethod(a: number, b: number) {
        return a + b;
    }
}
  1. 权限验证
    • 思路:创建一个权限验证装饰器,该装饰器可以从当前上下文(例如通过一个全局的用户信息对象)获取用户权限,然后判断用户是否有权限执行目标方法。如果没有权限,抛出一个错误或返回一个提示信息。
    • 关键代码示例
interface User {
    permissions: string[];
}

let currentUser: User = { permissions: ['view'] };

function checkPermission(requiredPermission: string) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        const originalMethod = descriptor.value;
        descriptor.value = function (...args: any[]) {
            if (!currentUser.permissions.includes(requiredPermission)) {
                throw new Error('Permission denied');
            }
            return originalMethod.apply(this, args);
        };
        return descriptor;
    };
}

class Resource {
    @checkPermission('edit')
    public editResource() {
        console.log('Resource edited');
    }
}