Node.js入门:Node.js 中的阻塞与非阻塞

193 阅读3分钟

大家好,我是前端理想哥!

今天是我们Node.js学习的第四节课,这节课我们来聊一聊Node.js 中“阻塞(Blocking)”和“非阻塞(Non-Blocking)”的区别,以及它们在实际开发中的影响。让我们一起搞懂如何在单线程环境下,提升吞吐量和并发能力!

一、什么是阻塞与非阻塞

我们先来解释一个概念,什么是阻塞?什么又是非阻塞?

  • 阻塞(Blocking)
    当需要执行的 JavaScript 逻辑必须等待某个非 JavaScript 操作(如 I/O)完成后,才能继续往下运行,这就叫阻塞。

    比如Node.js标准库中带 Sync 后缀的方法,常常会同步读取或写入文件,一旦调用就会卡住当前线程,直到操作结束才继续执行下一行代码。

  • 非阻塞(Non-Blocking)
    非阻塞方法在执行时,会让出主线程去做其他事情,等到 I/O 完成后,再通过回调函数(或 Promise)把结果返回。这样就可以在等待期间执行更多任务,不浪费时间。


二、对比示例

接下来,我们看一组对比示例。

我们要实现以下功能:使用Node.js的文件系统模块读取本地 file.md 文件

同步写法:

const fs = require('node:fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read

异步写法:

const fs = require('node:fs');

fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
});

以上代码都能实现我们的功能是吧?我们继续再拓展这两个例子

同步写法:

const fs = require('node:fs');
const data = fs.readFileSync('/file.md'); // 阻塞,直到文件读取完毕 
moreWork(); // 只有等待上面读取完成后才继续执行

异步写法:

const fs = require('node:fs');

fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});

moreWork(); // 不等待文件读取,直接执行

看到了吗?

同步的这种写法简单,逻辑直观,但是阻塞期间无法执行其他操作,主线程被“卡住”。

异步的写法能并行处理更多任务,大幅提升吞吐量。但是代码流程看起来不再是从上到下,需要使用回调来处理数据。

这就是两者的区别。

三、正确使用阻塞和非阻塞

对于阻塞和非阻塞,大家在日常开发使用中,一定要正确使用。

举个“危险”示例:

const fs = require('node:fs');

fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});

fs.unlinkSync('/file.md'); // 同步删除,可能比读取先执行

• 这里 unlinkSync() 很可能会在 readFile() 之前完成,导致文件被删掉了还没读取完。

正确做法:全程非阻塞

const fs = require('node:fs');

fs.readFile('/file.md', (readFileErr, data) => {
  if (readFileErr) throw readFileErr;
  console.log(data);
  fs.unlink('/file.md', (unlinkErr) => {
    if (unlinkErr) throw unlinkErr;
  });
});

• 这样保证了读取完再删除,顺序完全可控

四、如何选择

  1. 优先使用非阻塞异步方法

• 提高并发,让 Node.js 在等待 I/O 时不会闲置,可以同时处理更多任务。

  1. 避免不必要的同步调用

• 同步方法(尤其是带 Sync 后缀的)会直接阻塞主线程,不适合在高并发场景中频繁使用。

  1. 注意操作顺序

• 对操作先后顺序有依赖时,要么使用回调Promise/async-await来控制流程,要么确保所有相关操作都放在同一个异步链路里执行。

最后:

在 Node.js 里,玩转异步是提升性能与并发的关键。阻塞方法虽写起来简单,却可能让你的应用“卡到爆”;而非阻塞方法让主线程“腾出手”,提升吞吐量和用户体验。

记住:能用异步就别用同步,这是写 Node.js 的不二法门!

如果你觉得这些内容对你有帮助,记得点赞、收藏并分享,如果你有任何问题,欢迎在评论区讨论!

如果你也对 Node.js 感兴趣,记得关注理想哥,我们一起深入探索。