回调函数 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 的语法糖,让异步代码写得像同步一样,可读性最强。

相关推荐
IT_陈寒24 分钟前
Python 3.12 新特性实战:5个让你的代码效率提升50%的技巧!🔥
前端·人工智能·后端
Apifox25 分钟前
Apifox 8 月更新|新增测试用例、支持自定义请求示例代码、提升导入/导出 OpenAPI/Swagger 数据的兼容性
前端·后端·测试
weixin_5412999427 分钟前
VSCode: 从插件安装到配置,如何实现 Ctrl+S 保存时,完全按照 .eslintrc.js 中的 ESLint 规则自动格式化代码
javascript·ide·vscode
yw00yw27 分钟前
常见的设计模式
开发语言·javascript·设计模式
我们从未走散29 分钟前
设计模式学习笔记-----抽象责任链模式
java·笔记·学习·设计模式·责任链模式
coding随想33 分钟前
最后的挽留:深入浅出HTML5 beforeunload事件
前端
叶浩成52036 分钟前
WebSocket实时通信系统——js技能提升
javascript·websocket·网络协议
Magnetic_h43 分钟前
【iOS】内存管理及部分Runtime复习
笔记·学习·macos·ios·objective-c·cocoa·xcode
亚里士多德芙1 小时前
记录:离线包实现桥接
前端
去伪存真1 小时前
用的好好的vue.config.js代理,突然报308, 怎么回事?🤔
前端