MST
星途 面试题库

面试题:Node.js 文件系统操作优化之高级难度

假设你正在开发一个基于Node.js的文件处理应用,需要频繁地进行文件的读写和删除操作。在高并发场景下,如何通过合理地使用缓存、队列机制以及优化文件系统调用顺序来提升整体性能?阐述你的设计思路并给出关键代码片段。
29.2万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 缓存
    • 使用内存缓存(如 node-cache 库)来存储经常读取的文件内容。当需要读取文件时,先检查缓存中是否存在该文件内容。如果存在,直接从缓存中获取,避免文件系统的读取操作,减少I/O开销。
    • 对于文件删除操作,可以标记缓存中的对应文件为已删除,在一定时间内(或缓存清理时)再真正从缓存中移除,这样在后续可能的文件重新创建操作中,若在缓存有效期内,可快速复用缓存中的文件相关信息。
  2. 队列机制
    • 使用任务队列(如 async - queue 库)来管理文件操作任务。将文件的读写和删除操作放入队列中,按顺序执行,避免高并发下文件系统调用冲突。
    • 可以根据任务的优先级(例如,读取操作优先级高于删除操作)来调整任务在队列中的执行顺序。
  3. 优化文件系统调用顺序
    • 尽量批量处理文件操作。例如,在一次读取多个文件时,先构建文件路径列表,然后批量调用文件系统的读取函数,减少多次系统调用的开销。
    • 对于删除操作,若要删除多个文件,可以先将这些文件路径收集起来,然后批量执行删除操作。

关键代码片段

  1. 使用 node - cache 实现缓存
    const NodeCache = require('node-cache');
    const cache = new NodeCache();
    
    async function readFileWithCache(filePath) {
        let data = cache.get(filePath);
        if (data) {
            return data;
        }
        try {
            const fs = require('fs');
            data = await fs.promises.readFile(filePath, 'utf8');
            cache.set(filePath, data);
            return data;
        } catch (error) {
            console.error(`Error reading file ${filePath}:`, error);
            throw error;
        }
    }
    
  2. 使用 async - queue 实现任务队列
    const asyncQueue = require('async - queue');
    
    const fileOperationQueue = asyncQueue((task, callback) => {
        const { operation, filePath, data } = task;
        const fs = require('fs');
        if (operation ==='read') {
            fs.readFile(filePath, 'utf8', (err, content) => {
                if (err) {
                    console.error(`Error reading file ${filePath}:`, err);
                    callback(err);
                } else {
                    callback(null, content);
                }
            });
        } else if (operation === 'write') {
            fs.writeFile(filePath, data, (err) => {
                if (err) {
                    console.error(`Error writing file ${filePath}:`, err);
                    callback(err);
                } else {
                    callback(null);
                }
            });
        } else if (operation === 'delete') {
            fs.unlink(filePath, (err) => {
                if (err) {
                    console.error(`Error deleting file ${filePath}:`, err);
                    callback(err);
                } else {
                    callback(null);
                }
            });
        }
    }, 1); // 设置并发数为1,按顺序执行任务
    
    // 添加任务到队列
    function addFileOperationToQueue(operation, filePath, data) {
        fileOperationQueue.push({ operation, filePath, data }, (err, result) => {
            if (err) {
                console.error('Operation failed:', err);
            } else {
                console.log('Operation completed successfully:', result);
            }
        });
    }
    
  3. 批量文件操作示例
    async function batchReadFiles(filePaths) {
        const fs = require('fs');
        const promises = filePaths.map((filePath) => fs.promises.readFile(filePath, 'utf8'));
        return Promise.all(promises);
    }
    
    async function batchDeleteFiles(filePaths) {
        const fs = require('fs');
        const promises = filePaths.map((filePath) => fs.promises.unlink(filePath));
        return Promise.all(promises);
    }