回调函数 vs Promise vs async/await区别

回调函数(Callback)、Promise 和 async/await 都是 JavaScript 中处理 异步编程 的方式。

一、定义和基本写法

1. 回调函数(Callback)

概念:

把一个函数作为参数传给另一个函数,当异步操作完成后,再调用这个函数。

示例:

javascript 复制代码
function fetchData(callback) {
  setTimeout(() => {
    callback("数据已加载");
  }, 1000);
}

fetchData(function (data) {
  console.log(data); // 输出:数据已加载
});
  • 优点:

    • 语法简单,广泛使用。
  • 缺点:

    • 容易出现"回调地狱"或"嵌套地狱"。

    • 错误处理繁琐,容易遗漏。

2. Promise

概念:

Promise 是一个代表未来值的对象。它有三种状态:pending(进行中)、fulfilled(成功)、rejected(失败)。

示例:

javascript 复制代码
function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("数据已加载");
      // 或者 reject("加载失败");
    }, 1000);
  });
}

fetchData()
  .then((data) => console.log(data))      // 成功处理
  .catch((err) => console.error(err))     // 错误处理
  .finally(() => console.log("结束"));    // 无论成功或失败都执行
  • 优点:

    • 链式调用,减少嵌套。

    • 内置 .then(), .catch(), .finally() 更好组织代码。

  • 缺点:

    • 多层 .then() 嵌套仍然不够直观。

    • 错误捕获仍需特别注意。

3. async / await

概念:

是基于 Promise 的语法糖,让异步代码写起来更像同步,更简洁清晰。

示例:

javascript 复制代码
function fetchData() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("数据已加载");
    }, 1000);
  });
}

async function getData() {
  try {
    const data = await fetchData();
    console.log(data); // 输出:数据已加载
  } catch (err) {
    console.error(err); // 错误捕获
  } finally {
    console.log("结束");
  }
}

getData();
  • 优点:

    • 更接近同步代码的书写方式,逻辑更清晰。

    • 错误处理使用 try/catch,和同步代码一致。

  • 缺点:

    • 不能用在顶层作用域中(必须放在 async 函数里)。

    • 同时执行多个异步任务时不如 Promise.all 等组合方法直观。

二、优缺点对比

特性 回调函数 Promise async/await
引入年代 最早 ES6(2015) ES8(2017)
可读性 差(容易嵌套) 中等(链式) 高(接近同步代码)
控制流程 回调地狱(嵌套多层) 链式调用 .then() 线性流程,最直观
错误处理 不统一(靠手动处理) .catch() 统一处理 try/catch 统一处理
取消操作 不方便 可结合 AbortController 可结合 AbortController
并发执行 复杂 Promise.all 等很方便 可搭配 Promise 并发执行
兼容性 老浏览器兼容好 IE11 及以上 需要 Babel 转码支持

三、使用场景推荐

场景 推荐用法
旧项目/库或兼容性要求高 回调函数
多个异步并发或链式处理 Promise
写异步流程、结构清晰、易维护 async / await

四、实际对比举例

  • 回调嵌套(回调地狱)
javascript 复制代码
getUser(id, function(user) {
  getPosts(user.id, function(posts) {
    getComments(posts[0].id, function(comments) {
      console.log(comments);
    });
  });
});
  • Promise 链式优化
javascript 复制代码
getUser(id)
  .then(user => getPosts(user.id))
  .then(posts => getComments(posts[0].id))
  .then(comments => console.log(comments))
  .catch(err => console.error(err));
  • async/await 优雅写法
javascript 复制代码
async function showComments(id) {
  try {
    const user = await getUser(id);
    const posts = await getPosts(user.id);
    const comments = await getComments(posts[0].id);
    console.log(comments);
  } catch (err) {
    console.error(err);
  }
}

五、总结

  • 回调函数 是最原始的异步方式,但会导致 回调地狱。

  • Promise 更加优雅,支持 链式调用与统一错误处理。

  • async/await 是基于 Promise 的语法糖,让异步代码写得像同步一样,可读性最强。

相关推荐
Eiceblue4 分钟前
【免费.NET方案】CSV到PDF与DataTable的快速转换
开发语言·pdf·c#·.net
m0_5557629036 分钟前
Matlab 频谱分析 (Spectral Analysis)
开发语言·matlab
像风一样自由20201 小时前
HTML与JavaScript:构建动态交互式Web页面的基石
前端·javascript·html
巴伦是只猫1 小时前
【机器学习笔记Ⅰ】13 正则化代价函数
人工智能·笔记·机器学习
aiprtem1 小时前
基于Flutter的web登录设计
前端·flutter
浪裡遊2 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
why技术2 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
GISer_Jing2 小时前
0704-0706上海,又聚上了
前端·新浪微博
止观止2 小时前
深入探索 pnpm:高效磁盘利用与灵活的包管理解决方案
前端·pnpm·前端工程化·包管理器
whale fall2 小时前
npm install安装的node_modules是什么
前端·npm·node.js