Skip to content

Node.js 核心特性面试题

Node.js 核心特性涵盖事件循环、模块系统、异步编程等后端开发的关键概念。

🔥 Node.js 核心面试题

1. 事件循环和异步编程模型

问题:详细解释Node.js的事件循环机制,以及与浏览器事件循环的区别。

参考答案

javascript
// Node.js 事件循环阶段
console.log('=== Node.js 事件循环示例 ===');

// 1. 同步代码
console.log('1. 同步代码开始');

// 2. timer阶段 - setTimeout
setTimeout(() => {
  console.log('4. setTimeout - timer阶段');
}, 0);

// 3. I/O阶段 - setImmediate
setImmediate(() => {
  console.log('5. setImmediate - check阶段');
});

// 4. process.nextTick - 微任务队列优先级最高
process.nextTick(() => {
  console.log('2. process.nextTick - 微任务');
});

// 5. Promise - 微任务队列
Promise.resolve().then(() => {
  console.log('3. Promise.then - 微任务');
});

console.log('1. 同步代码结束');

// 事件循环详细实现
class SimpleEventLoop {
  constructor() {
    this.timerQueue = [];
    this.immediateQueue = [];
    this.nextTickQueue = [];
    this.promiseQueue = [];
    this.running = false;
  }
  
  // 模拟setTimeout
  setTimeout(callback, delay) {
    const timer = {
      callback,
      executeTime: Date.now() + delay
    };
    this.timerQueue.push(timer);
    this.timerQueue.sort((a, b) => a.executeTime - b.executeTime);
  }
  
  // 模拟setImmediate
  setImmediate(callback) {
    this.immediateQueue.push(callback);
  }
  
  // 模拟process.nextTick
  nextTick(callback) {
    this.nextTickQueue.push(callback);
  }
  
  // 模拟Promise
  resolvePromise(callback) {
    this.promiseQueue.push(callback);
  }
  
  // 执行微任务
  flushMicrotasks() {
    // process.nextTick 优先级最高
    while (this.nextTickQueue.length > 0) {
      const callback = this.nextTickQueue.shift();
      callback();
    }
    
    // Promise 微任务
    while (this.promiseQueue.length > 0) {
      const callback = this.promiseQueue.shift();
      callback();
    }
  }
  
  // 事件循环主体
  run() {
    this.running = true;
    
    while (this.running) {
      // 1. Timer 阶段
      const now = Date.now();
      while (this.timerQueue.length > 0 && this.timerQueue[0].executeTime <= now) {
        const timer = this.timerQueue.shift();
        timer.callback();
        this.flushMicrotasks(); // 每个宏任务后执行微任务
      }
      
      // 2. I/O 回调阶段(简化)
      // 这里会处理网络、文件系统等I/O回调
      
      // 3. Check 阶段 - setImmediate
      while (this.immediateQueue.length > 0) {
        const callback = this.immediateQueue.shift();
        callback();
        this.flushMicrotasks(); // 每个宏任务后执行微任务
      }
      
      // 如果没有待执行的任务,退出循环
      if (this.timerQueue.length === 0 && 
          this.immediateQueue.length === 0 &&
          this.nextTickQueue.length === 0 &&
          this.promiseQueue.length === 0) {
        this.running = false;
      }
    }
  }
}

// 实际应用:异步流控制
class AsyncFlowControl {
  // 串行执行异步任务
  static async series(tasks) {
    const results = [];
    for (const task of tasks) {
      const result = await task();
      results.push(result);
    }
    return results;
  }
  
  // 并行执行异步任务
  static async parallel(tasks) {
    return Promise.all(tasks.map(task => task()));
  }
  
  // 限制并发数的并行执行
  static async parallelLimit(tasks, limit) {
    const results = [];
    const executing = [];
    
    for (const task of tasks) {
      const promise = task().then(result => {
        results.push(result);
        executing.splice(executing.indexOf(promise), 1);
        return result;
      });
      
      results.push(promise);
      executing.push(promise);
      
      if (executing.length >= limit) {
        await Promise.race(executing);
      }
    }
    
    await Promise.all(executing);
    return Promise.all(results);
  }
  
  // 瀑布流执行
  static async waterfall(tasks, initialValue) {
    let result = initialValue;
    for (const task of tasks) {
      result = await task(result);
    }
    return result;
  }
}

// 使用示例
async function demonstrateAsyncFlow() {
  const createAsyncTask = (name, delay) => {
    return () => new Promise(resolve => {
      setTimeout(() => {
        console.log(`任务 ${name} 完成`);
        resolve(`结果${name}`);
      }, delay);
    });
  };
  
  const tasks = [
    createAsyncTask('A', 1000),
    createAsyncTask('B', 500),
    createAsyncTask('C', 800)
  ];
  
  console.log('串行执行:');
  const seriesResults = await AsyncFlowControl.series(tasks);
  console.log('串行结果:', seriesResults);
  
  console.log('并行执行:');
  const parallelResults = await AsyncFlowControl.parallel([
    createAsyncTask('D', 1000),
    createAsyncTask('E', 500),
    createAsyncTask('F', 800)
  ]);
  console.log('并行结果:', parallelResults);
  
  console.log('限制并发(2):');
  const limitResults = await AsyncFlowControl.parallelLimit([
    createAsyncTask('G', 1000),
    createAsyncTask('H', 500),
    createAsyncTask('I', 800),
    createAsyncTask('J', 300)
  ], 2);
  console.log('限制并发结果:', limitResults);
}

2. 模块系统和包管理

问题:Node.js的模块系统工作原理,CommonJS与ES Modules的区别?

参考答案

javascript
// 1. CommonJS 模块系统
// math.js
function add(a, b) {
  return a + b;
}

function multiply(a, b) {
  return a * b;
}

class Calculator {
  constructor() {
    this.history = [];
  }
  
  calculate(operation, a, b) {
    let result;
    switch (operation) {
      case 'add':
        result = add(a, b);
        break;
      case 'multiply':
        result = multiply(a, b);
        break;
      default:
        throw new Error('不支持的操作');
    }
    
    this.history.push({ operation, a, b, result });
    return result;
  }
}

// 导出方式1:module.exports
module.exports = {
  add,
  multiply,
  Calculator
};

// 导出方式2:exports(注意限制)
// exports.add = add;
// exports.multiply = multiply;

// 导出方式3:混合导出
module.exports = Calculator;
module.exports.add = add;
module.exports.multiply = multiply;

// 2. 模块加载和缓存机制
// main.js
const math = require('./math');
const math2 = require('./math'); // 从缓存中加载

console.log(math === math2); // true - 同一个引用

// 模块加载路径解析
// require('./math')      -> 相对路径
// require('/abs/math')   -> 绝对路径  
// require('lodash')      -> node_modules
// require('math/calc')   -> node_modules/math/calc

// 3. ES Modules (Node.js 14+)
// math.mjs 或 package.json中type: "module"
export function add(a, b) {
  return a + b;
}

export function multiply(a, b) {
  return a * b;
}

export default class Calculator {
  constructor() {
    this.history = [];
  }
}

// 命名导出和重新导出
export { add as sum, multiply };
export * from './utilities.mjs';

// main.mjs
import Calculator, { add, multiply as mult } from './math.mjs';
import * as mathUtils from './math.mjs';

// 动态导入
const math = await import('./math.mjs');

// 4. 模块系统实现原理
class ModuleSystem {
  constructor() {
    this.cache = new Map();
  }
  
  require(id) {
    // 1. 检查缓存
    if (this.cache.has(id)) {
      return this.cache.get(id).exports;
    }
    
    // 2. 创建模块对象
    const module = {
      id,
      exports: {},
      loaded: false,
      children: [],
      parent: null
    };
    
    // 3. 加入缓存
    this.cache.set(id, module);
    
    // 4. 加载模块内容
    const source = this.loadSource(id);
    
    // 5. 包装代码
    const wrapper = `
      (function(exports, require, module, __filename, __dirname) {
        ${source}
      });
    `;
    
    // 6. 编译执行
    const compiledWrapper = eval(wrapper);
    const require = (childId) => this.require(childId);
    
    compiledWrapper.call(
      module.exports,
      module.exports,
      require,
      module,
      id,
      path.dirname(id)
    );
    
    // 7. 标记已加载
    module.loaded = true;
    
    return module.exports;
  }
  
  loadSource(id) {
    // 模拟读取文件内容
    const fs = require('fs');
    return fs.readFileSync(id, 'utf8');
  }
}

// 5. 包管理实践
// package.json配置
const packageConfig = {
  "name": "my-node-app",
  "version": "1.0.0",
  "type": "module", // 启用ES Modules
  "main": "index.js",
  "exports": {
    ".": {
      "import": "./index.mjs",
      "require": "./index.cjs"
    },
    "./utils": {
      "import": "./utils/index.mjs",
      "require": "./utils/index.cjs"
    }
  },
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "jest",
    "build": "tsc"
  },
  "dependencies": {
    "express": "^4.18.0",
    "lodash": "^4.17.21"
  },
  "devDependencies": {
    "nodemon": "^2.0.15",
    "jest": "^27.5.1"
  },
  "engines": {
    "node": ">=14.0.0"
  }
};

// 6. 高级模块模式
// 单例模式
class DatabaseConnection {
  constructor() {
    if (DatabaseConnection.instance) {
      return DatabaseConnection.instance;
    }
    
    this.connected = false;
    DatabaseConnection.instance = this;
  }
  
  connect() {
    if (!this.connected) {
      console.log('建立数据库连接');
      this.connected = true;
    }
    return this;
  }
}

module.exports = new DatabaseConnection();

// 工厂模式
class LoggerFactory {
  static createLogger(type) {
    switch (type) {
      case 'console':
        return new ConsoleLogger();
      case 'file':
        return new FileLogger();
      case 'database':
        return new DatabaseLogger();
      default:
        throw new Error(`不支持的日志类型: ${type}`);
    }
  }
}

// 依赖注入容器
class DIContainer {
  constructor() {
    this.services = new Map();
    this.singletons = new Map();
  }
  
  register(name, factory, options = {}) {
    this.services.set(name, { factory, options });
  }
  
  resolve(name) {
    const service = this.services.get(name);
    if (!service) {
      throw new Error(`服务未注册: ${name}`);
    }
    
    if (service.options.singleton) {
      if (!this.singletons.has(name)) {
        this.singletons.set(name, service.factory(this));
      }
      return this.singletons.get(name);
    }
    
    return service.factory(this);
  }
}

// 使用依赖注入
const container = new DIContainer();

container.register('database', () => new DatabaseConnection(), { singleton: true });
container.register('userService', (container) => {
  return new UserService(container.resolve('database'));
}, { singleton: true });

const userService = container.resolve('userService');

3. 流(Streams)和文件系统

问题:Node.js中流的概念和应用场景,以及文件系统操作的最佳实践?

参考答案

javascript
const fs = require('fs');
const { Readable, Writable, Transform, pipeline } = require('stream');
const { promisify } = require('util');
const path = require('path');

// 1. 自定义可读流
class NumberStream extends Readable {
  constructor(options, max = 10) {
    super(options);
    this.current = 1;
    this.max = max;
  }
  
  _read() {
    if (this.current <= this.max) {
      this.push(`数字: ${this.current}\n`);
      this.current++;
    } else {
      this.push(null); // 结束流
    }
  }
}

// 2. 自定义可写流
class UpperCaseWriter extends Writable {
  constructor(options) {
    super(options);
  }
  
  _write(chunk, encoding, callback) {
    const upperCased = chunk.toString().toUpperCase();
    process.stdout.write(upperCased);
    callback();
  }
}

// 3. 自定义转换流
class JSONTransform extends Transform {
  constructor(options) {
    super(options);
    this.objectMode = true;
  }
  
  _transform(chunk, encoding, callback) {
    try {
      const obj = JSON.parse(chunk.toString());
      obj.timestamp = new Date().toISOString();
      obj.processed = true;
      this.push(JSON.stringify(obj) + '\n');
      callback();
    } catch (error) {
      callback(error);
    }
  }
}

// 4. 流的实际应用
class FileProcessor {
  // 大文件读取处理
  static async processLargeFile(inputPath, outputPath) {
    return new Promise((resolve, reject) => {
      const readStream = fs.createReadStream(inputPath, { 
        encoding: 'utf8',
        highWaterMark: 16 * 1024 // 16KB chunks
      });
      
      const writeStream = fs.createWriteStream(outputPath);
      const transformer = new Transform({
        transform(chunk, encoding, callback) {
          // 处理每个数据块
          const processed = chunk.toString()
            .replace(/old/g, 'new')
            .toUpperCase();
          callback(null, processed);
        }
      });
      
      // 使用pipeline确保错误处理
      pipeline(readStream, transformer, writeStream, (error) => {
        if (error) {
          console.error('Pipeline失败:', error);
          reject(error);
        } else {
          console.log('Pipeline成功完成');
          resolve();
        }
      });
    });
  }
  
  // CSV数据处理
  static processCSV(inputPath) {
    const readStream = fs.createReadStream(inputPath, { encoding: 'utf8' });
    let buffer = '';
    
    return new Promise((resolve, reject) => {
      const results = [];
      
      readStream.on('data', (chunk) => {
        buffer += chunk;
        const lines = buffer.split('\n');
        
        // 保留最后一行(可能不完整)
        buffer = lines.pop();
        
        lines.forEach(line => {
          if (line.trim()) {
            const data = line.split(',');
            results.push({
              id: data[0],
              name: data[1],
              email: data[2]
            });
          }
        });
      });
      
      readStream.on('end', () => {
        // 处理最后的buffer
        if (buffer.trim()) {
          const data = buffer.split(',');
          results.push({
            id: data[0],
            name: data[1],
            email: data[2]
          });
        }
        resolve(results);
      });
      
      readStream.on('error', reject);
    });
  }
  
  // 文件上传处理
  static handleFileUpload(req, uploadDir) {
    return new Promise((resolve, reject) => {
      const filename = `upload_${Date.now()}.tmp`;
      const filepath = path.join(uploadDir, filename);
      const writeStream = fs.createWriteStream(filepath);
      
      let totalSize = 0;
      const maxSize = 10 * 1024 * 1024; // 10MB限制
      
      req.on('data', (chunk) => {
        totalSize += chunk.length;
        if (totalSize > maxSize) {
          writeStream.destroy();
          fs.unlink(filepath, () => {});
          reject(new Error('文件太大'));
          return;
        }
        
        writeStream.write(chunk);
      });
      
      req.on('end', () => {
        writeStream.end();
        resolve({ filepath, filename, size: totalSize });
      });
      
      req.on('error', (error) => {
        writeStream.destroy();
        fs.unlink(filepath, () => {});
        reject(error);
      });
    });
  }
}

// 5. 文件系统操作封装
class FileSystemUtils {
  // 递归创建目录
  static async ensureDir(dirPath) {
    try {
      await fs.promises.access(dirPath);
    } catch (error) {
      await fs.promises.mkdir(dirPath, { recursive: true });
    }
  }
  
  // 递归删除目录
  static async removeDir(dirPath) {
    try {
      const files = await fs.promises.readdir(dirPath);
      
      for (const file of files) {
        const filePath = path.join(dirPath, file);
        const stat = await fs.promises.stat(filePath);
        
        if (stat.isDirectory()) {
          await this.removeDir(filePath);
        } else {
          await fs.promises.unlink(filePath);
        }
      }
      
      await fs.promises.rmdir(dirPath);
    } catch (error) {
      if (error.code !== 'ENOENT') {
        throw error;
      }
    }
  }
  
  // 复制文件
  static async copyFile(source, destination) {
    await this.ensureDir(path.dirname(destination));
    
    return new Promise((resolve, reject) => {
      const readStream = fs.createReadStream(source);
      const writeStream = fs.createWriteStream(destination);
      
      pipeline(readStream, writeStream, (error) => {
        if (error) {
          reject(error);
        } else {
          resolve();
        }
      });
    });
  }
  
  // 获取目录大小
  static async getDirSize(dirPath) {
    let totalSize = 0;
    
    const files = await fs.promises.readdir(dirPath);
    
    for (const file of files) {
      const filePath = path.join(dirPath, file);
      const stat = await fs.promises.stat(filePath);
      
      if (stat.isDirectory()) {
        totalSize += await this.getDirSize(filePath);
      } else {
        totalSize += stat.size;
      }
    }
    
    return totalSize;
  }
  
  // 文件监控
  static watchDirectory(dirPath, callback) {
    const watcher = fs.watch(dirPath, { recursive: true }, (eventType, filename) => {
      if (filename) {
        const filePath = path.join(dirPath, filename);
        callback(eventType, filePath);
      }
    });
    
    return watcher;
  }
  
  // 安全的JSON文件读写
  static async readJSONFile(filePath) {
    try {
      const data = await fs.promises.readFile(filePath, 'utf8');
      return JSON.parse(data);
    } catch (error) {
      if (error.code === 'ENOENT') {
        return null;
      }
      throw error;
    }
  }
  
  static async writeJSONFile(filePath, data) {
    await this.ensureDir(path.dirname(filePath));
    const jsonData = JSON.stringify(data, null, 2);
    await fs.promises.writeFile(filePath, jsonData, 'utf8');
  }
}

// 6. 使用示例
async function demonstrateStreams() {
  // 创建流
  const numberStream = new NumberStream({}, 5);
  const upperWriter = new UpperCaseWriter();
  
  // 管道操作
  numberStream.pipe(upperWriter);
  
  // 处理文件
  try {
    await FileProcessor.processLargeFile('input.txt', 'output.txt');
    
    const csvData = await FileProcessor.processCSV('data.csv');
    console.log('CSV数据:', csvData);
    
    const dirSize = await FileSystemUtils.getDirSize('./uploads');
    console.log(`上传目录大小: ${dirSize} 字节`);
    
    // 监控文件变化
    const watcher = FileSystemUtils.watchDirectory('./watched', (eventType, filePath) => {
      console.log(`文件 ${eventType}: ${filePath}`);
    });
    
    // 5秒后停止监控
    setTimeout(() => {
      watcher.close();
    }, 5000);
    
  } catch (error) {
    console.error('操作失败:', error);
  }
}

// demonstrateStreams();

这些Node.js核心特性面试题涵盖了服务端JavaScript开发的关键概念,展示了对Node.js生态系统的深入理解和实际应用能力。

正在精进