异步等待在JavaScript中是如何工作的

79 阅读2分钟

Async/await有时被称为Promises之上的 "语法糖"。但这到底是什么意思?答案其实很简单:Async/await实际上只是引擎盖下的promises,但有不同的(有人会说更简单)语法。

让我们使用一个非常常见的承诺的例子:获取数据。

用承诺获取数据

我们将首先使用浏览器内置的fetch 函数。当你把一个URL传给fetch ,它返回一个承诺。一旦该承诺与响应一起解析,我们就可以对该响应使用.json() 方法来返回另一个承诺。该承诺将与请求响应的json体进行解析。

下面是所有这些从GitHub公共API中获取用户数据的动作。

fetch('https://api.github.com/users/nas5w')
  .then((res) => res.json())
  .then((data) => {
    console.log(data);
  })
  .catch((err) => {
    console.error(err);
  });

/*

{
  "login": "nas5w",
  "id": 7538045,
  "node_id": "MDQ6VXNlcjc1MzgwNDU=",
  "avatar_url": "https://avatars2.githubusercontent.com/u/7538045?v=4",
  "gravatar_id": "",
  "url": "https://api.github.com/users/nas5w",
  "html_url": "https://github.com/nas5w",
  "followers_url": "https://api.github.com/users/nas5w/followers",
  "following_url": "https://api.github.com/users/nas5w/following{/other_user}",
  "gists_url": "https://api.github.com/users/nas5w/gists{/gist_id}",
  "starred_url": "https://api.github.com/users/nas5w/starred{/owner}{/repo}",
  "subscriptions_url": "https://api.github.com/users/nas5w/subscriptions",
  "organizations_url": "https://api.github.com/users/nas5w/orgs",
  "repos_url": "https://api.github.com/users/nas5w/repos",
  "events_url": "https://api.github.com/users/nas5w/events{/privacy}",
  "received_events_url": "https://api.github.com/users/nas5w/received_events",
  "type": "User",
  "site_admin": false,
  "name": "Nick Scialli",
  "company": null,
  "blog": "http://www.twitter.com/nas5w",
  "location": "Washington, DC",
  "email": null,
  "hireable": null,
  "bio": "Husband, dog dad, software engineer, and data science enthusiast.\r\n",
  "twitter_username": null,
  "public_repos": 44,
  "public_gists": 1,
  "followers": 249,
  "following": 5,
  "created_at": "2014-05-09T21:05:01Z",
  "updated_at": "2020-11-28T15:41:35Z"
}

*/

很好,如果你对承诺很熟悉的话,这可能是很简单的。

添加异步等待

由于async/await仍然使用承诺,我们可以使用同样的例子我喜欢认为async/await的方式是,我们告诉我们的解释器,一个函数是异步的(async),在该函数中,我们将等待(await)一个承诺(或多个承诺)的解决,然后继续前进。

让我们看看我的意思。

// This is an asynchronous function
async function getGithubData() {
  // Let's wait for the promise returned from fetch to resolve
  const res = await fetch('https://api.github.com/users/nas5w');
  // Let's wait for the promise returned from res.json() to resolve
  const data = await res.json();
  // Now we have our data, let's log it
  console.log(data);
}

你可能会注意到,如果你试图运行这个,什么也不会发生!这是因为我们把它藏在了一个小盒子里。这是因为我们把这段代码塞进了一个异步函数中*,但*我们从未调用过那个函数。我们可以继续调用它,我们应该得到和以前一样的控制台输出。

getGithubData();

这下好了现在还有最后一步:我们需要处理任何错误通过承诺,我们能够使用承诺.catch 方法。有了async/await,我们将用try/catch块来包装一切。

async function getGithubData() {
  try {
    const res = await fetch('https://api.github.com/users/nas5w');
    const data = await res.json();
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

getGithubData();

现在你已经将一个承诺转换为async/await的语法了!