Node.js最开始让我觉得比较奇怪的地方,就是它大量使用异步代码。

以前写同步代码的时候,程序基本按着:

第一步
 ↓
第二步
 ↓
第三步

往下走。

但Node.js里经常看到:

await request()
await readFile()
await queryDatabase()

理解了异步机制之后,这些代码就没那么神秘了。

为什么需要异步

假设程序要读一个文件:

读取文件
 ↓
等磁盘
 ↓
返回结果

如果程序在等的时候什么事都干不了,那服务器资源的利用率就很低。

网络请求也是一样:

请求API
 ↓
等服务器
 ↓
收到响应

等待可能需要几十毫秒甚至几秒。

Node.js的设计就是要尽量避免这种I/O等待把整个程序卡住。

Promise

现代JavaScript里,Promise是异步编程的基础之一。

比如:

const promise = fetch('/api/users')

Promise可以理解成:

一个未来可能会拿到结果的对象。

它有几种状态:

pending
   ↓
fulfilled

或者

pending
   ↓
rejected

所以可以:

promise
  .then(result => {
    console.log(result)
  })
  .catch(error => {
    console.error(error)
  })

async/await

Promise本身没问题。

但异步操作一多:

getUser()
  .then(user => {
    getOrders(user.id)
      .then(orders => {
        // ...
      })
  })

代码就越来越难读了。

async/await可以把代码写得跟同步写法更像:

const user = await getUser()
const orders = await getOrders(user.id)

但要注意:

async/await并没有把异步变成同步。

它只是改变了代码的写法。

try/catch处理异步错误

比如:

try {
  const user = await getUser()
  console.log(user)
} catch (error) {
  console.error(error)
}

这样可以集中处理Promise rejected的情况。

API服务里经常能看到这种结构。

别无脑串行await

下面这段:

const user = await getUser()
const settings = await getSettings()
const notifications = await getNotifications()

如果三个请求互相不依赖,那其实没必要等前一个结束再开始下一个。

可以:

const [
  user,
  settings,
  notifications
] = await Promise.all([
  getUser(),
  getSettings(),
  getNotifications()
])

这样三个请求可以并行跑。

这在项目里是一个很常见的性能优化点。

Event Loop

Node.js的核心之一就是事件循环。

可以简单理解成:

JavaScript
    ↓
Event Loop
    ↓
处理任务
    ↓
等I/O
    ↓
继续处理其他任务

比如:

console.log('A')

setTimeout(() => {
  console.log('B')
}, 0)

console.log('C')

输出并不是:

A
B
C

而是:

A
C
B

因为setTimeout的回调不会立即执行。

它会进到后面的任务流程里。

为什么CPU密集型代码会成为问题

Node.js很适合I/O。

但如果执行:

while (true) {
  // 非常重的计算
}

那事件循环就被占死了。

其他请求也可能没法及时处理。

所以:

Node.js的优势不是"JavaScript能同时跑很多CPU计算"。

而是:

它非常擅长处理大量异步I/O。

Promise.all也不能乱用

虽然:

Promise.all()

很方便,但也不能无限并发。

比如一次请求几万个URL:

await Promise.all(
  urls.map(url => fetch(url))
)

很可能直接造成:

  • 网络连接过多
  • 内存上涨
  • 对方服务器压力过大
  • 本机资源耗尽

这时候应该做并发控制。

比如限制同时执行的任务数量。

我现在对异步代码的理解

异步编程不是为了把代码写得更复杂。

它真正解决的是:

等I/O

这种操作不应该把整个程序卡住。

理解了:

Promise
async/await
Event Loop
并发

之后,Node.js的很多行为就容易理解了。

尤其是在API服务、爬虫、批量请求这些场景里,正确处理异步操作会直接影响程序的性能和稳定性。

所以对于Node.js开发来说,我觉得:

理解异步模型比记住几个API更重要。

最后修改:2026 年 09 月 02 日
如果觉得我的文章对你有用,请随意赞赏