MST

星途 面试题库

面试题:Node.js 中异步编程如何处理多个并发任务

在 Node.js 项目里,假设有多个 I/O 操作(比如读取多个文件)需要并发执行,执行完后将所有结果汇总处理。请使用合适的异步编程方法(如 Promise、async/await 等)实现这个场景,并阐述这样做的好处以及可能遇到的问题。
32.3万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

实现代码

const fs = require('fs');
const path = require('path');
const { promisify } = require('util');

// 将 fs.readFile 转化为 Promise 形式
const readFileAsync = promisify(fs.readFile);

// 假设要读取的文件路径数组
const filePaths = [
  path.join(__dirname, 'file1.txt'),
  path.join(__dirname, 'file2.txt'),
  path.join(__dirname, 'file3.txt')
];

async function readFilesConcurrently() {
  try {
    // 使用 Promise.all 并发读取文件
    const results = await Promise.all(filePaths.map(filePath => readFileAsync(filePath, 'utf8')));
    // 汇总处理结果
    const summary = results.join(' ');
    console.log('汇总结果:', summary);
    return summary;
  } catch (error) {
    console.error('读取文件时出错:', error);
  }
}

readFilesConcurrently();

好处

  1. 提高效率:通过并发执行多个 I/O 操作,充分利用系统资源,减少等待时间,大大提高程序整体执行效率。比如在读取多个文件时,无需一个一个顺序读取,而是同时发起多个读取请求。
  2. 代码可读性增强:使用 Promise 和 async/await 使得异步代码看起来更像同步代码,逻辑更加清晰。相比于传统的回调函数嵌套(回调地狱),代码结构更易于理解和维护。例如在上述代码中,await 使得代码等待 Promise 被解决后再继续执行,符合人类阅读和编写同步代码的习惯。
  3. 错误处理方便:通过 try...catch 块可以统一捕获和处理所有并发操作中抛出的错误,而不像回调函数那样每个回调都要单独处理错误。在上述代码中,try...catch 可以捕获 Promise.all 中任何一个 readFileAsync 操作抛出的错误。

可能遇到的问题

  1. 内存消耗:如果并发的 I/O 操作过多,可能会导致内存消耗过大。例如同时读取大量大文件,会占用较多内存用于存储读取的数据。这可能会导致程序性能下降甚至内存溢出。
  2. 资源竞争:在并发操作中,如果多个操作同时访问和修改共享资源(虽然在读取文件场景中较少出现,但在其他涉及共享资源的 I/O 操作中可能出现),可能会导致数据不一致等问题。需要使用锁机制或其他同步手段来避免资源竞争。
  3. 调试困难:尽管 Promise 和 async/await 使代码更易读,但并发操作本身的复杂性可能会使调试变得困难。例如难以确定错误具体发生在哪个并发操作中,因为所有操作都在同时执行。