MST

星途 面试题库

面试题:Node.js Express生产环境的性能优化策略

请详细说明在Node.js Express应用处于生产环境时,如何通过缓存策略(如HTTP缓存、内存缓存等)以及异步处理优化来提升性能,每种策略至少列举两种具体的实现方式。
47.0万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

HTTP缓存策略

  1. 设置Cache - Control头
    • 在Express应用中,可以通过res.set('Cache - Control', 'public, max - age = 31536000')设置响应头。public表示响应可以被任何中间节点(如浏览器、CDN等)缓存,max - age设置缓存的有效时间为31536000秒(一年)。这适用于不经常变化的静态资源,如CSS、JavaScript文件等。
    • 对于动态生成但变化不频繁的数据,可以设置Cache - Control: s - maxage = 3600, stale - while - revalidate = 600s - maxage用于共享缓存(如CDN)设置缓存时间为3600秒,stale - while - revalidate表示在缓存过期后,仍可以使用过期的缓存内容600秒,同时后台去重新验证和更新数据。
  2. ETag头
    • 使用express - etag中间件,它会自动为响应生成ETag头。例如:
    const express = require('express');
    const etag = require('express - etag');
    const app = express();
    app.use(etag());
    app.get('/data', (req, res) => {
        const data = { message: 'Some data' };
        res.json(data);
    });
    
    • 手动计算ETag,比如对于一个JSON响应数据,可以这样计算:
    const crypto = require('crypto');
    app.get('/data', (req, res) => {
        const data = { message: 'Some data' };
        const jsonData = JSON.stringify(data);
        const etagValue = crypto.createHash('sha256').update(jsonData).digest('hex');
        res.set('ETag', etagValue);
        res.json(data);
    });
    
    • 客户端再次请求时,如果ETag没有变化,服务器可以返回304 Not Modified状态码,减少数据传输。

内存缓存策略

  1. 使用node - cache
    • 安装:npm install node - cache
    • 使用示例:
    const NodeCache = require('node - cache');
    const myCache = new NodeCache();
    const express = require('express');
    const app = express();
    app.get('/cachedData', (req, res) => {
        const cacheKey = 'cachedDataKey';
        const cachedData = myCache.get(cacheKey);
        if (cachedData) {
            return res.json(cachedData);
        }
        const newData = { message: 'Fresh data' };
        myCache.set(cacheKey, newData);
        res.json(newData);
    });
    
    • 可以设置缓存过期时间,如myCache.set(cacheKey, newData, 60),这里60表示60秒后缓存过期。
  2. 基于Map对象手动实现简单缓存
    const express = require('express');
    const app = express();
    const cache = new Map();
    app.get('/cachedValue', (req, res) => {
        const key = 'cachedValueKey';
        if (cache.has(key)) {
            const cachedValue = cache.get(key);
            return res.json(cachedValue);
        }
        const newValue = { result: 'New value' };
        cache.set(key, newValue);
        res.json(newValue);
    });
    
    • 可以添加逻辑来定期清理缓存,比如使用setInterval,模拟缓存过期机制:
    const express = require('express');
    const app = express();
    const cache = new Map();
    const cacheDuration = 60 * 1000; // 60 seconds
    setInterval(() => {
        const now = Date.now();
        cache.forEach((value, key, map) => {
            if (now - value.timestamp > cacheDuration) {
                map.delete(key);
            }
        });
    }, cacheDuration);
    app.get('/cachedValue', (req, res) => {
        const key = 'cachedValueKey';
        if (cache.has(key)) {
            const cachedValue = cache.get(key).value;
            return res.json(cachedValue);
        }
        const newValue = { result: 'New value' };
        cache.set(key, { value: newValue, timestamp: Date.now() });
        res.json(newValue);
    });
    

异步处理优化

  1. 使用async/await
    • 对于数据库查询,假设使用mysql2库:
    const express = require('express');
    const mysql = require('mysql2');
    const app = express();
    const connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: 'password',
        database: 'test'
    });
    app.get('/users', async (req, res) => {
        try {
            const [rows] = await connection.promise().query('SELECT * FROM users');
            res.json(rows);
        } catch (error) {
            console.error(error);
            res.status(500).send('Error fetching data');
        }
    });
    
    • 对于文件读取操作,使用fs/promises
    const express = require('express');
    const fs = require('fs/promises');
    const app = express();
    app.get('/fileContent', async (req, res) => {
        try {
            const content = await fs.readFile('test.txt', 'utf8');
            res.send(content);
        } catch (error) {
            console.error(error);
            res.status(500).send('Error reading file');
        }
    });
    
  2. 使用Promise.all
    • 当需要并行执行多个异步操作,比如同时获取多个API的数据:
    const express = require('express');
    const axios = require('axios');
    const app = express();
    app.get('/combinedData', async (req, res) => {
        const api1Promise = axios.get('https://api.example.com/data1');
        const api2Promise = axios.get('https://api.example.com/data2');
        try {
            const [response1, response2] = await Promise.all([api1Promise, api2Promise]);
            const combinedData = { data1: response1.data, data2: response2.data };
            res.json(combinedData);
        } catch (error) {
            console.error(error);
            res.status(500).send('Error fetching data');
        }
    });