当前位置: 首页 > article >正文

JavaScript系列(42)--路由系统实现详解

JavaScript路由系统实现详解 🛣️

今天,让我们深入探讨JavaScript的路由系统实现。路由系统是现代单页应用(SPA)中的核心组件,它负责管理视图的切换和状态的维护。

路由系统基础概念 🌟

💡 小知识:路由系统是单页应用中负责URL管理和视图切换的核心机制,它能够在不刷新页面的情况下更新视图内容。

基本实现 📊

// 1. 基础路由器
class SimpleRouter {
    constructor() {
        this.routes = new Map();
        this.currentRoute = null;
        
        // 监听浏览器历史记录变化
        window.addEventListener('popstate', () => {
            this.handleRoute(window.location.pathname);
        });
    }
    
    addRoute(path, handler) {
        this.routes.set(path, handler);
    }
    
    removeRoute(path) {
        this.routes.delete(path);
    }
    
    navigate(path) {
        window.history.pushState({}, '', path);
        this.handleRoute(path);
    }
    
    handleRoute(path) {
        const handler = this.routes.get(path);
        if (handler) {
            this.currentRoute = path;
            handler();
        } else {
            console.warn(`No handler found for path: ${path}`);
        }
    }
}

// 2. 支持参数的路由器
class ParameterizedRouter {
    constructor() {
        this.routes = [];
        this.currentRoute = null;
        
        window.addEventListener('popstate', () => {
            this.handleRoute(window.location.pathname);
        });
    }
    
    addRoute(pattern, handler) {
        const regex = this.patternToRegex(pattern);
        this.routes.push({ pattern, regex, handler });
    }
    
    patternToRegex(pattern) {
        return new RegExp(
            '^' + pattern.replace(/:[^\s/]+/g, '([^/]+)') + '$'
        );
    }
    
    navigate(path) {
        window.history.pushState({}, '', path);
        this.handleRoute(path);
    }
    
    handleRoute(path) {
        for (const route of this.routes) {
            const match = path.match(route.regex);
            if (match) {
                const params = this.extractParams(route.pattern, match);
                this.currentRoute = path;
                route.handler(params);
                return;
            }
        }
        console.warn(`No handler found for path: ${path}`);
    }
    
    extractParams(pattern, match) {
        const params = {};
        const paramNames = pattern.match(/:[^\s/]+/g) || [];
        paramNames.forEach((param, index) => {
            params[param.slice(1)] = match[index + 1];
        });
        return params;
    }
}

// 3. 路由守卫
class GuardedRouter extends ParameterizedRouter {
    constructor() {
        super();
        this.guards = [];
    }
    
    addGuard(guard) {
        this.guards.push(guard);
    }
    
    async navigate(path) {
        // 执行所有守卫
        for (const guard of this.guards) {
            const canProceed = await guard(path);
            if (!canProceed) {
                console.warn(`Navigation to ${path} was blocked by a guard`);
                return;
            }
        }
        
        super.navigate(path);
    }
}

高级功能实现 🚀

// 1. 嵌套路由
class NestedRouter {
    constructor() {
        this.routes = new Map();
        this.children = new Map();
        this.parent = null;
    }
    
    addRoute(path, handler) {
        this.routes.set(path, handler);
    }
    
    addChild(path, router) {
        router.parent = this;
        this.children.set(path, router);
    }
    
    async handleRoute(path) {
        // 检查是否有直接匹配的路由
        const handler = this.routes.get(path);
        if (handler) {
            await handler();
            return true;
        }
        
        // 检查子路由
        for (const [prefix, childRouter] of this.children) {
            if (path.startsWith(prefix)) {
                const remainingPath = path.slice(prefix.length);
                const handled = await childRouter.handleRoute(remainingPath);
                if (handled) return true;
            }
        }
        
        return false;
    }
}

// 2. 路由中间件
class MiddlewareRouter {
    constructor() {
        this.routes = new Map();
        this.middlewares = [];
    }
    
    use(middleware) {
        this.middlewares.push(middleware);
    }
    
    addRoute(path, handler) {
        this.routes.set(path, handler);
    }
    
    async handleRoute(path) {
        const handler = this.routes.get(path);
        if (!handler) {
            console.warn(`No handler found for path: ${path}`);
            return;
        }
        
        const context = { path, handled: false };
        
        // 执行中间件链
        const chain = [...this.middlewares, async (ctx, next) => {
            await handler();
            ctx.handled = true;
            await next();
        }];
        
        await this.executeMiddlewareChain(chain, context);
    }
    
    async executeMiddlewareChain(middlewares, context) {
        let prevIndex = -1;
        
        const runner = async (index) => {
            if (index === prevIndex) {
                throw new Error('next() called multiple times');
            }
            
            prevIndex = index;
            
            const middleware = middlewares[index];
            if (middleware) {
                await middleware(context, () => runner(index + 1));
            }
        };
        
        await runner(0);
    }
}

// 3. 路由状态管理
class StatefulRouter {
    constructor() {
        this.routes = new Map();
        this.state = new Map();
        
        window.addEventListener('popstate', (event) => {
            if (event.state) {
                this.state = new Map(Object.entries(event.state));
            }
            this.handleRoute(window.location.pathname);
        });
    }
    
    addRoute(path, handler) {
        this.routes.set(path, handler);
    }
    
    setState(key, value) {
        this.state.set(key, value);
    }
    
    getState(key) {
        return this.state.get(key);
    }
    
    navigate(path, state = {}) {
        this.state = new Map(Object.entries(state));
        window.history.pushState(
            Object.fromEntries(this.state),
            '',
            path
        );
        this.handleRoute(path);
    }
    
    handleRoute(path) {
        const handler = this.routes.get(path);
        if (handler) {
            handler(Object.fromEntries(this.state));
        } else {
            console.warn(`No handler found for path: ${path}`);
        }
    }
}

性能优化技巧 ⚡

// 1. 路由缓存
class CachedRouter {
    constructor() {
        this.routes = new Map();
        this.cache = new Map();
        this.maxCacheSize = 10;
    }
    
    addRoute(path, handler) {
        this.routes.set(path, handler);
    }
    
    async handleRoute(path) {
        // 检查缓存
        if (this.cache.has(path)) {
            const cached = this.cache.get(path);
            if (!this.isCacheExpired(cached)) {
                return cached.content;
            }
            this.cache.delete(path);
        }
        
        const handler = this.routes.get(path);
        if (handler) {
            const content = await handler();
            this.cacheRoute(path, content);
            return content;
        }
    }
    
    cacheRoute(path, content) {
        // 如果缓存已满,删除最旧的条目
        if (this.cache.size >= this.maxCacheSize) {
            const oldestKey = this.cache.keys().next().value;
            this.cache.delete(oldestKey);
        }
        
        this.cache.set(path, {
            content,
            timestamp: Date.now()
        });
    }
    
    isCacheExpired(cached) {
        const maxAge = 5 * 60 * 1000; // 5分钟
        return Date.now() - cached.timestamp > maxAge;
    }
}

// 2. 路由预加载
class PreloadRouter {
    constructor() {
        this.routes = new Map();
        this.preloadQueue = new Set();
    }
    
    addRoute(path, handler, preloadCondition) {
        this.routes.set(path, {
            handler,
            preloadCondition
        });
    }
    
    async checkPreloadConditions() {
        for (const [path, route] of this.routes) {
            if (route.preloadCondition && 
                route.preloadCondition() && 
                !this.preloadQueue.has(path)) {
                this.preloadQueue.add(path);
                this.preloadRoute(path);
            }
        }
    }
    
    async preloadRoute(path) {
        const route = this.routes.get(path);
        if (route) {
            try {
                await route.handler();
                console.log(`Preloaded route: ${path}`);
            } catch (error) {
                console.error(`Failed to preload route: ${path}`, error);
            }
        }
    }
}

// 3. 路由分片
class ChunkedRouter {
    constructor() {
        this.chunks = new Map();
        this.loadedChunks = new Set();
    }
    
    defineChunk(name, routes) {
        this.chunks.set(name, routes);
    }
    
    async loadChunk(name) {
        if (this.loadedChunks.has(name)) {
            return;
        }
        
        const chunk = this.chunks.get(name);
        if (chunk) {
            await chunk();
            this.loadedChunks.add(name);
        }
    }
    
    async handleRoute(path) {
        // 确定路由所属的chunk
        const chunkName = this.getChunkForPath(path);
        if (chunkName) {
            await this.loadChunk(chunkName);
        }
    }
    
    getChunkForPath(path) {
        // 实现路由到chunk的映射逻辑
        // 这里可以使用正则表达式或其他匹配方式
    }
}

最佳实践建议 💡

  1. 路由组织模式
// 1. 模块化路由
class ModularRouter {
    constructor() {
        this.modules = new Map();
    }
    
    registerModule(name, routes) {
        this.modules.set(name, routes);
    }
    
    async loadModule(name) {
        const module = this.modules.get(name);
        if (module) {
            await module.initialize();
        }
    }
}

// 2. 路由配置管理
class RouteConfig {
    constructor() {
        this.config = new Map();
    }
    
    addConfig(path, options) {
        this.validateConfig(options);
        this.config.set(path, options);
    }
    
    validateConfig(options) {
        const requiredFields = ['component', 'auth'];
        for (const field of requiredFields) {
            if (!(field in options)) {
                throw new Error(`Missing required field: ${field}`);
            }
        }
    }
}

// 3. 错误处理
class ErrorBoundaryRouter {
    constructor() {
        this.routes = new Map();
        this.errorHandlers = new Map();
    }
    
    addErrorHandler(errorType, handler) {
        this.errorHandlers.set(errorType, handler);
    }
    
    async handleRoute(path) {
        try {
            const handler = this.routes.get(path);
            if (handler) {
                await handler();
            }
        } catch (error) {
            await this.handleError(error);
        }
    }
    
    async handleError(error) {
        for (const [ErrorType, handler] of this.errorHandlers) {
            if (error instanceof ErrorType) {
                await handler(error);
                return;
            }
        }
        
        // 默认错误处理
        console.error('Unhandled router error:', error);
    }
}

结语 📝

路由系统是现代JavaScript单页应用的核心组件,通过本文,我们学习了:

  1. 路由系统的基本概念和实现
  2. 高级功能如嵌套路由和中间件
  3. 性能优化技巧
  4. 最佳实践和错误处理策略
  5. 路由配置和模块化管理

💡 学习建议:在实践中,要根据应用的规模和需求选择合适的路由实现方案。对于小型应用,简单的路由器就足够了;对于大型应用,则需要考虑使用更完整的路由解决方案,包括代码分割、路由守卫等特性。


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

终身学习,共同成长。

咱们下一期见

💻


http://www.kler.cn/a/516120.html

相关文章:

  • 利用Kubespray安装生产环境的k8s集群-排错篇
  • npm install 报错:Command failed: git checkout 2.2.0-c
  • 网络(一)
  • 《安富莱嵌入式周报》第349期:VSCode正式支持Matlab调试,DIY录音室级麦克风,开源流体吊坠,物联网在军工领域的应用,Unicode字符压缩解压
  • opentelemetry-collector docker安装
  • 机器学习10-解读CNN代码Pytorch版
  • 2025.1.20——二、buuctf BUU UPLOAD COURSE 1 1 文件上传
  • 详解单片机学的是什么?(电子硬件)
  • Redis面试题每日20道【其一】
  • AI智慧社区--生成验证码
  • 【CPH系列】RFID标签读取模块,开发说明文档(包含重要内容和BUG)
  • K8S 启动探测、就绪探测、存活探测
  • 软考信安27~Windows操作系统安全相关
  • k8s服务StatefulSet部署模板
  • 如何用概率论解决真实问题?用随机变量去建模,最大的难题是相关关系
  • CAS简解
  • 怎么解决Visual Studio中两个cpp文件中相同函数名重定义问题
  • 【github 使用相关】提交pr和commit message Conventional Commits 规范 代码提交的描述该写什么?
  • 【C++】详细讲解继承(上)
  • 【网络协议】【http】【https】ECDHE-TLS1.2
  • 领域驱动设计(DDD)四 订单管理系统实践步骤
  • 【时时三省】(C语言基础)格式化输入输出函数
  • 2025.1.21——六、BUU XSS COURSE 1
  • P1115 最大子段和
  • 人工智能在音频、视觉、多模态领域的应用
  • 踏浪而行,2024年技术创作的星光轨迹