5 分钟了解 JavaScript 的 Async + Await

2025-06-07

5 分钟了解 JavaScript 的 Async + Await

告别 Promise 的初始阶段和回调狂潮!👋🎉

你可能在 JavaScript 中遇到过 Promises(如果你还没有,可以快速查看本指南👍 )。它们允许你钩住异步调用的完成。它们使得链接异步操作甚至将它们组合在一起变得非常简单。但有一个小小的缺点:使用 Promises 时,语法并不总是最优雅的。

引入async + await 🎉

对于TL;DR 阵营的人来说, async+await是消耗你的Promise代码的语法糖 🍭 它们有助于理解代码流程。没有什么新概念,只是Promise穿着更漂亮的鞋子而已 👟 向下滚动查看gist⌨️

用代码烤蛋糕🍰

我们要烤蛋糕🍰 真好吃!要烤蛋糕,我们首先需要准备好食材。不好意思,这只是一块普通的海绵蛋糕😅

  • 黄油
  • 面粉
  • 鸡蛋🥚

在我们的代码中,获取每种成分都需要异步操作。

例如,方法如下getButter

const getButter = () => new Promise((resolve, reject) => {
  setTimeout(() => resolve('Butter'), 3000)
})
Enter fullscreen mode Exit fullscreen mode

这些操作将成为方法的一部分getIngredients。当我们烘焙蛋糕时,我们需要getIngredients在搅拌之前调用它,等等。

带着承诺

假设我们需要链接每个异步操作。getIngredients这是一次在超市里挑选一种食材的旅程🛒

大多数情况下,只有当操作相互依赖时,我们才需要将它们链接起来。例如,如果第二个操作需要第一个操作的返回值,依此类推。

在我们的例子中,我们可能一次只能将一件商品添加到购物篮中。这意味着我们需要逐一处理所有配料。请记住,这里的代码是假设的,只是为了展示 Promises 的用法 😉

用 Promise 实现起来会怎么样getIngredients?我以前肯定见过这种嵌套的 Promise 👀

const getIngredients = () => new Promise((resolve, reject) => {
  getButter().then((butter) => {
    updateBasket(butter)
    getFlour().then((flour) => {
      updateBasket(flour)
      getSugar().then((sugar) => {
        updateBasket(sugar)
        getEggs().then((eggs) => {
          updateBasket(eggs)
          resolve(basket)
        })
      })
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

这可以工作,但看起来不太好👎如果使用 Promise 链看起来会更好。

const getIngredients = () => getButter()
  .then(updateBasket)
  .then(getFlour)
  .then(updateBasket)
  .then(getSugar)
  .then(updateBasket)
  .then(getEggs)
  .then(updateBasket)
Enter fullscreen mode Exit fullscreen mode

如果我们在网上购物,我们可以使用Promise.all🤓

const getIngredients = () => Promise.all([
  getButter(),
  getFlour(),
  getSugar(),
  getEggs(),
])
Enter fullscreen mode Exit fullscreen mode

这些看起来整洁多了,但我们仍然需要使用回调来获取这些成分。

getIngredients().then(ingredients => doSomethingWithIngredients(ingredients))
Enter fullscreen mode Exit fullscreen mode

使用 async + await 进行整理

让我们来点缀一下语法糖🍭 要使用await关键字,我们必须先用 关键字将方法声明为异步方法async。需要注意的是,async方法总是会返回Promise。这意味着没有必要返回Promise🎉

让我们声明getIngredients为异步

const getIngredients = async () => {}
Enter fullscreen mode Exit fullscreen mode

现在,这些Promises 加上语法糖会是什么样子呢?await关键字允许我们等待 a Promise,并定义一个变量,该变量的返回值是Promise。对于这个例子来说,这有点冗长,但让我们把这个语法糖应用到 上getIngredients

const getIngredients = async () => {
  const butter = await getButter()
  const flour = await getFlour()
  const sugar = await getSugar()
  const eggs = await getEggs()
  return [
    butter,
    flour,
    sugar,
    eggs,
  ]
}
Enter fullscreen mode Exit fullscreen mode

代码并没有变小,但更冗长简洁了👍 不再有回调。只有当我们使用 aPromise时,语法糖才会发挥作用。

const bakeACake = async () => {
  const ingredients = await getIngredients()
  // do something with the ingredients, no more ".then" 🙌
}
Enter fullscreen mode Exit fullscreen mode

哇!😎 干净到什么程度?

使用asyncandawait使我们的代码更加程序化和全面。它看起来更简洁,功能也完全相同。需要记住的是,我们并没有替换Promises,我们仍然在幕后使用它们。现在,我们用一种更简洁的新语法来使用它们。

是的,这也适用Promise.all。所以,如果我们在线购物,我们的代码会更小。

const getIngredients = async () => {
  const ingredients = await Promise.all([
    getButter(),
    getFlour(),
    getSugar(),
    getEggs(),
  ])
  return ingredients
}
Enter fullscreen mode Exit fullscreen mode

我们不再需要那个包装函数了!

const getIngredients = async () =>
  await Promise.all([getButter(), getFlour(), getSugar(), getEggs()]);
Enter fullscreen mode Exit fullscreen mode

等待非承诺

如果您所指向的值await不是,该怎么办?在我们的示例中,异步函数在之后Promise返回StringsetTimeout

const egg = await 🥚
Enter fullscreen mode Exit fullscreen mode

不会有任何错误,该值变为已解决状态Promise😅

被拒绝了怎么办?

到目前为止,我们已经处理了快乐之路😃但是如果Promise拒绝的话该怎么办?

比如,如果库存中没有鸡蛋怎么办?我们的异步函数 forgetEggs将会被拒绝,并可能出现错误。

为了解决这个问题,一个简单的try/catch语句就可以了👍

const getIngredients = async () => {
  try {
    const butter = await 'Butter'
    const flour = await getFlour()
    const sugar = await getSugar()
    const eggs = await getEggs()
    return [
      butter,
      flour,
      sugar,
      eggs,
    ]
  } catch(e) { return e }
}
Enter fullscreen mode Exit fullscreen mode

我们可以在这个级别或更高级别进行包装,然后调用getIngredients👍

使用我们的功能并烘焙蛋糕🍰

如果你已经读到这里,我们已经getIngredients用 new async+await关键字创建了 for 函数。剩下的部分看起来会是什么样子呢?

const bakeACake = async () => {
  try {
    // get the ingredients
    const ingredients = await getIngredients()
    // mix them together
    const cakeMix = await mix(ingredients)
    // put in oven on 180C, gas mark 4for 20-25 minutes
    const hotCake = await cook(cakeMix)
    // allow to stand before serving
    const cake = await stand(hotCake)
    return cake
  } catch (e) { return e }
}
Enter fullscreen mode Exit fullscreen mode

比我们之前用 s 做的要干净得多Promise🎉

就这样!5分钟用 async + await 烤个蛋糕🍰

如果您已经读到这里,感谢您的阅读😃我整理了一个要点,其中包含一些可能的示例代码,可以在下面看到,以及一些有关async+的进一步资源await

重要的要点⚠️;

  • async函数总是返回Promise
  • await在大多数情况下将被用来对付一个Promise或一Promise
  • 使用try/catch语句处理任何潜在错误👍
  • 我们还没有谈到这一点,但你可以awaitawait发出fetch请求时,你可能会先await发出请求,然后再发出await函数json
const data = await (await fetch(`${dataUrl}`)).json()
Enter fullscreen mode Exit fullscreen mode

一如既往,如果您有任何问题或建议,请随时留言或发推文给我🐦!记得在社交媒体上关注我😎

const PROB = 0.2
const grabIngredient = ingredient => () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > PROB) {
resolve(ingredient)
} else {
reject(`Sorry, we've got no ${ingredient}`)
}
}, Math.random() * 1000)
})
}
// boilerplate functions for getting the different ingredients
const getButter = grabIngredient('Butter')
const getFlour = grabIngredient('Flour')
const getSugar = grabIngredient('Sugar')
const getEggs = grabIngredient('Eggs')
const getIngredientsFromTheSuperMarket = async () => {
try {
const butter = await getButter()
const flour = await getFlour()
const sugar = await getSugar()
const eggs = await getEggs()
return [
butter,
flour,
sugar,
eggs,
]
} catch(e) { return e }
}
const getIngredientsOnline = async () => await Promise.all([
getButter(),
getFlour(),
getSugar(),
getEggs(),
])
// boilerplate async functions that return strings
const mix = async (ingredients) => `Mixing ${ingredients}`
const cook = async (cakeMix) => 'Hot Cake'
const stand = async (hotCake) => '🍰'
const bakeACake = async () => {
try {
const ingredients = await getIngredientsOnline()
const cakeMix = await mix(ingredients)
const hotCake = await cook(cakeMix)
const cake = await stand(hotCake)
console.info('BAKED', cake)
return cake
} catch (e) { console.info(e) }
}
bakeACake()
view raw bakeACake.js hosted with ❤ by GitHub
const PROB = 0.2
const grabIngredient = ingredient => () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > PROB) {
resolve(ingredient)
} else {
reject(`Sorry, we've got no ${ingredient}`)
}
}, Math.random() * 1000)
})
}
// boilerplate functions for getting the different ingredients
const getButter = grabIngredient('Butter')
const getFlour = grabIngredient('Flour')
const getSugar = grabIngredient('Sugar')
const getEggs = grabIngredient('Eggs')
const getIngredientsFromTheSuperMarket = async () => {
try {
const butter = await getButter()
const flour = await getFlour()
const sugar = await getSugar()
const eggs = await getEggs()
return [
butter,
flour,
sugar,
eggs,
]
} catch(e) { return e }
}
const getIngredientsOnline = async () => await Promise.all([
getButter(),
getFlour(),
getSugar(),
getEggs(),
])
// boilerplate async functions that return strings
const mix = async (ingredients) => `Mixing ${ingredients}`
const cook = async (cakeMix) => 'Hot Cake'
const stand = async (hotCake) => '🍰'
const bakeACake = async () => {
try {
const ingredients = await getIngredientsOnline()
const cakeMix = await mix(ingredients)
const hotCake = await cook(cakeMix)
const cake = await stand(hotCake)
console.info('BAKED', cake)
return cake
} catch (e) { console.info(e) }
}
bakeACake()
view raw bakeACake.js hosted with ❤ by GitHub

更多资源

文章来源:https://dev.to/jh3y/javascript-s-async-await-in-5-minutes-3e6d
PREV
5 分钟学会 React Hooks 它们是什么? 👟 useState 为什么不使用 class? 📗 其他 Hooks useEffect 关注点分离 创建自定义 Hooks 注意事项 👍 注意事项 👎 注意事项 ⚠️ 就是这样!
NEXT
如何:光标跟踪视差