MST

星途 面试题库

面试题:JavaScript 中优化 Node HTTP 服务器性能之路由优化

在 Node HTTP 服务器中使用 JavaScript 开发,当有大量路由时,如何优化路由查找性能?请举例说明常用的优化方法。
29.7万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试
  1. 使用路由表数据结构
    • 说明:将路由信息存储在合适的数据结构中,如哈希表(JavaScript 中的对象本质类似哈希表)。这样在查找路由时可以通过哈希值快速定位,而无需逐个遍历。
    • 示例
const http = require('http');
const url = require('url');

// 路由表
const routeTable = {
    '/home': (req, res) => {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('This is the home page');
    },
    '/about': (req, res) => {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('This is the about page');
    }
};

const server = http.createServer((req, res) => {
    const parsedUrl = url.parse(req.url, true);
    const route = routeTable[parsedUrl.pathname];
    if (route) {
        route(req, res);
    } else {
        res.writeHead(404, {'Content-Type': 'text/plain'});
        res.end('404 Not Found');
    }
});

const port = 3000;
server.listen(port, () => {
    console.log(`Server running on port ${port}`);
});
  1. 路由分组与前缀树(Trie 树)
    • 说明:对于有相同前缀的路由,可以进行分组。前缀树可以高效地处理这种情况,它通过共享前缀节点来减少查找时间。虽然在 JavaScript 中没有原生的前缀树数据结构,但可以自己实现。
    • 示例:以简单的手动实现类似前缀树的逻辑为例(实际实现前缀树会更复杂):
const http = require('http');
const url = require('url');

// 路由分组对象
const routes = {
    '/api': {
        '/users': (req, res) => {
            res.writeHead(200, {'Content-Type': 'text/plain'});
            res.end('List of users');
        },
        '/products': (req, res) => {
            res.writeHead(200, {'Content-Type': 'text/plain'});
            res.end('List of products');
        }
    }
};

const server = http.createServer((req, res) => {
    const parsedUrl = url.parse(req.url, true);
    const parts = parsedUrl.pathname.split('/').filter(part => part);
    let current = routes;
    for (let i = 0; i < parts.length; i++) {
        const part = `/${parts[i]}`;
        if (current[part]) {
            if (i === parts.length - 1) {
                current[part](req, res);
                return;
            }
            current = current[part];
        } else {
            break;
        }
    }
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end('404 Not Found');
});

const port = 3000;
server.listen(port, () => {
    console.log(`Server running on port ${port}`);
});
  1. 缓存路由查找结果
    • 说明:对于静态路由(不随请求参数变化的路由),可以缓存查找结果。在后续相同路由请求时,直接从缓存中获取处理函数,减少查找开销。
    • 示例:使用简单的 JavaScript 对象作为缓存:
const http = require('http');
const url = require('url');

// 路由表
const routeTable = {
    '/home': (req, res) => {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('This is the home page');
    },
    '/about': (req, res) => {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('This is the about page');
    }
};

// 缓存对象
const routeCache = {};

const server = http.createServer((req, res) => {
    const parsedUrl = url.parse(req.url, true);
    const route = routeCache[parsedUrl.pathname];
    if (route) {
        route(req, res);
    } else {
        const handler = routeTable[parsedUrl.pathname];
        if (handler) {
            routeCache[parsedUrl.pathname] = handler;
            handler(req, res);
        } else {
            res.writeHead(404, {'Content-Type': 'text/plain'});
            res.end('404 Not Found');
        }
    }
});

const port = 3000;
server.listen(port, () => {
    console.log(`Server running on port ${port}`);
});