← 返回目录

JavaScript 异步编程:回调、Promise 与 Async/Await

进阶 · 第 6 篇 ·

为什么需要异步

JavaScript 是单线程语言,同一时间只能执行一个任务。如果用同步方式发起网络请求,浏览器会「卡住」直到请求完成。异步编程让 JS 可以在等待耗时操作时继续执行其他代码。

回调函数(Callback)

function fetchData(url, callback) {
  setTimeout(() => {
    callback(null, { data: '结果' });
  }, 1000);
}

fetchData('/api/user', (err, data) => {
  if (err) { console.error('失败:', err); return; }
  console.log('成功:', data);
});

Promise

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功的结果');
  }, 1000);
});

myPromise
  .then(result => console.log(result))
  .catch(err => console.error(err))
  .finally(() => console.log('完成'));

Promise 静态方法

// 并行执行,全部成功才成功
Promise.all([fetch(url1), fetch(url2)])
  .then(([res1, res2]) => console.log('全部完成'));

// 并行执行,返回最快的结果
Promise.race([fetch(url1), fetch(url2)])
  .then(fastest => console.log('最快完成'));

Async/Await

async function getUser() {
  try {
    const response = await fetch('/api/user');
    const data = await response.json();
    console.log(data);
    return data;
  } catch (error) {
    console.error('请求失败:', error);
  }
}

并行请求

// 串行(慢)
const a = await fetch('/api/a');
const b = await fetch('/api/b');

// 并行(快)
const [a, b] = await Promise.all([
  fetch('/api/a'),
  fetch('/api/b'),
]);

实战:防抖与节流

// 防抖:停止操作后才执行
function debounce(fn, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

// 节流:固定间隔只执行一次
function throttle(fn, interval) {
  let last = 0;
  return function(...args) {
    const now = Date.now();
    if (now - last >= interval) {
      last = now;
      fn.apply(this, args);
    }
  };
}

// 使用
input.addEventListener('input', debounce((e) => {
  console.log('搜索:', e.target.value);
}, 300));

小结

本篇从回调函数到 Promise 再到 async/await,梳理了 JS 异步编程的演进。async/await 是当前最佳实践,配合 Promise 静态方法可以优雅处理复杂的异步流程。

下一篇:响应式设计:移动优先与媒体查询