JavaScript 是单线程语言,异步是它最核心的设计之一。掌握异步编程,是真正理解 JS 的必经之路。

从回调开始

最早的异步方案是回调函数

fs.readFile('data.txt', function(err, data) {
  if (err) throw err;
  console.log(data);
});

问题在于,当异步操作嵌套多层,代码就成了臭名昭著的”回调地狱”:

getData(function(a) {
  getMoreData(a, function(b) {
    getEvenMoreData(b, function(c) {
      // ...这里还有更深的嵌套
    });
  });
});

可读性和可维护性极差。

Promise 的出现

ES6 引入了 Promise,将异步操作的状态(pending / fulfilled / rejected)显式化:

fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(err => console.error(err));

链式调用替代了嵌套,代码更线性。

async/await — 同步风格写异步

ES2017 引入的 async/await 是目前最推荐的方式:

async function loadData() {
  try {
    const response = await fetch('/api/data');
    const data = await response.json();
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

看起来和同步代码几乎一样,心智负担大幅降低。

并行执行

当多个异步操作互不依赖时,用 Promise.all 并行执行:

const [users, posts] = await Promise.all([
  fetchUsers(),
  fetchPosts()
]);

这比顺序执行快得多。

总结

方案 时代 优点 缺点
回调 ES5 简单直接 嵌套混乱
Promise ES6 链式清晰 稍显冗长
async/await ES2017 同步风格,可读性强 需理解 Promise 基础

现代项目中,async/await + Promise.all 几乎能覆盖所有异步场景。