如何从异步调用中返回结果:JavaScript 完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

“我调用了一个函数,但它返回 undefined!”——熟悉的心痛吗?

\n

想象一下:你在编写 JavaScript 代码,向 API 发起请求,等待数据……但返回的却是 undefined。或者更糟——Promise {<pending>}。你垂头丧气,想关掉浏览器去当和尚。

\n

别急。这个问题连经验丰富的开发者都会困扰。难怪 Stack Overflow 上的问题 “How do I return the response from an asynchronous call?” 获得了数千次浏览和数百个回答。今天我们就一劳永逸地解决它。

\n

在本文中,你将了解到:

\n
    \n
  • 为什么 return 不像你习惯的那样工作
  • \n
  • 如何通过回调、Promise 和 async/await 驯服异步操作
  • \n
  • 为你的项目选择哪种方法
  • \n
\n

开始吧!

\n\n

为什么 return 不返回数据?

\n

我们直接进入正题。这是一个经典示例:

\n\n
function getUserData(userId) {\n  fetch(`https://api.example.com/users/${userId}`)\n    .then(response => response.json())\n    .then(data => {\n      return data; // 看起来没问题?\n    });\n}\n\nconst user = getUserData(42);\nconsole.log(user); // undefined
\n\n

熟悉吗?你在 .then() 内部写了 return data,但在外部却得到了 undefined。为什么?

\n

JavaScript 是单线程且非阻塞的。 当你调用 fetch 时,它不会等待服务器响应。相反,它将回调的执行“搁置”到一边,并立即转到下一行代码。而下一行是 console.log(user),此时 user 尚未定义。

\n

你的 getUserData 函数在服务器响应返回之前就结束了。它没有返回任何内容(返回 undefined),而数据则“悬在空中”。

\n

如何解决?有三种主要方法。

\n\n

方法 1:回调(Callbacks)——异步的鼻祖

\n

在过去,Promise 出现之前,所有异步操作都通过回调完成。你传递一个函数,当数据到达时该函数会被调用。

\n\n
function getUserData(userId, callback) {\n  fetch(`https://api.example.com/users/${userId}`)\n    .then(response => response.json())\n    .then(data => {\n      callback(data); // 用数据调用回调\n    })\n    .catch(error => {\n      callback(null, error); // 或者传递错误\n    });\n}\n\n// 使用方式:\ngetUserData(42, (data, error) => {\n  if (error) {\n    console.error('错误:', error);\n    return;\n  }\n  console.log('用户数据:', data);\n});
\n\n

优点: 简单,随处可用。

\n

缺点: 如果嵌套多个回调,就会形成“回调地狱”(callback hell)。代码变得难以阅读。

\n\n
getUserData(42, (data1) => {\n  getPosts(data1.id, (data2) => {\n    getComments(data2[0].id, (data3) => {\n      // ... 以此类推\n    });\n  });\n});
\n\n

现代 JavaScript 已经摆脱了这种写法。但理解回调仍然必要——它们是所有其他方法的基础。

\n\n

方法 2:Promise(承诺)——可读性的救星

\n

Promise 是一个对象,它代表一个“承诺”在未来返回某个值。它有三种状态:pending(等待中)、fulfilled(已完成)和 rejected(已拒绝)。

\n

回到我们的示例。我们不使用回调,而是直接返回 Promise 本身:

\n\n
function getUserData(userId) {\n  return fetch(`https://api.example.com/users/${userId}`)\n    .then(response => {\n      if (!response.ok) {\n        throw new Error('网络异常');\n      }\n      return response.json();\n    });\n}\n\n// 使用方式:\nconst userPromise = getUserData(42);\n\nuserPromise\n  .then(data => {\n    console.log('用户数据:', data);\n  })\n                

博客

书籍推荐