用 async 和 await 编写现代 JavaScript 异步代码 – JavaScript 完全手册(2018版)

10年服务1亿前端开发工程师

小编推荐:掘金是一个面向程序员的高质量技术社区,从 一线大厂经验分享到前端开发最佳实践,无论是入门还是进阶,来掘金你不会错过前端开发的任何一个技术干货。

注:本文为 《 JavaScript 完全手册(2018版) 》第26节,你可以查看该手册的完整目录。

现在,我们将探索 JavaScript 中更现代的异步函数方法。 JavaScript 在很短的时间内从回调演变为 Promises ,从 ES2017(ES8) 开始,使用 async/await 语法让异步 JavaScript 变得更简单。

async(异步) 函数是 promises 和 generator 的组合,基本上,它们是对 promises 的更高级别的抽象。让我再说一遍:async/await 基于 promises

为什么要引入 async/await ?

它们降低了 promises 对一些固定语法样板的要求,打破了链式 promise “不能切断链式”的限制。

在 ES2015 中引入 Promise 时,它们旨在解决异步代码的问题,并且他们确实做到了,但在 ES2015 和 ES2017 的两年中,人们发现很明显 promises 不是最终的解决方案。

引入 Promises 来解决著名的回调地狱问题,但是因为他们自身的复杂性,引入了更复杂的语法。

它们是良好的原语,可以向开发人员公开更好的语法,所以当时机成熟时,我们就有了 异步函数(async functions)

它们使代码看起来像是同步,但它在后台是异步和非阻塞的。

工作原理

async(异步) 函数返回一个 promise,如下例所示:

const doSomethingAsync = () => {
    return new Promise((resolve) => {
        setTimeout(() => resolve('I did something'), 3000)
    })
}

当你想要 调用 这个函数时,你在前面加上 await ,并且 调用代码将停止,直到 promise 被resolved 或者 rejected 。一个警告:调用函数必须定义为 async 。这里有一个例子:

const doSomething = async () => {
    console.log(await doSomethingAsync())
}

一个简单的例子

这是使用 async/await 异步运行函数的简单示例:

const doSomethingAsync = () => {
    return new Promise((resolve) => {
        setTimeout(() => resolve('I did something'), 3000)
    })
}

const doSomething = async () => {
    console.log(await doSomethingAsync())
}

console.log('Before')
doSomething()
console.log('After')

上面的代码将浏览器控制台中打印以下内容:

Before
After
I did something //after 3s

一切都是 promise

async 关键字添加到任何函数,意味着该函数将返回一个 promise 。

即使它没有明确的这么写出来,在内部也会使函数返回一个 promise 。

这就是此代码有效的原因:

const aFunction = async () => {
  return 'test'
}
aFunction().then(alert) // This will alert 'test'

并且与下面的代码等价:

const aFunction = async () => {
  return Promise.resolve('test')
}
aFunction().then(alert) // This will alert 'test'

代码更易于阅读

正如您在上面的示例中看到的,我们的代码看起来非常简单。 将它与使用链式调用和回调函数的普通 promise 的代码进行比较。

这是一个非常简单的例子,当代码越复杂,越能凸显它的优势。

例如,以下是使用 promises 获取 JSON 资源并解析它的方法:

const getFirstUserData = () => {
  return fetch('/users.json') // get users list
    .then(response => response.json()) // parse JSON
    .then(users => users[0]) // pick first user
    .then(user => fetch(`/users/${user.name}`)) // get user data
    .then(userResponse => response.json()) // parse JSON
}
getFirstUserData()

以下是使用 async/await 实现的相同功能:

const getFirstUserData = async () => {
  const response = await fetch('/users.json') // get users list
  const users = await response.json() // parse JSON
  const user = users[0] // pick first user
  const userResponse = await fetch(`/users/${user.name}`) // get user data
  const userData = await user.json() // parse JSON
  return userData
}

getFirstUserData()

链接多个 async(异步) 函数

async(异步) 函数可以非常容易地链接起来,并且语法比简单的 promise 更具可读性:

const promiseToDoSomething = () => {
    return new Promise(resolve => {
        setTimeout(() => resolve('I did something'), 10000)
    })
}
const watchOverSomeoneDoingSomething = async () => {
    const something = await promiseToDoSomething()
    return something + ' and I watched'
}
const watchOverSomeoneWatchingSomeoneDoingSomething = async () => {
    const something = await watchOverSomeoneDoingSomething()
    return something + ' and I watched as well'
}
watchOverSomeoneWatchingSomeoneDoingSomething().then((res) => {
    console.log(res)
})

将打印:

I did something and I watched and I watched as well

更容易调试

调试 promise 很难,因为调试器不能跳过异步代码。

Async/await 使得调试非常简单,因为对编译器来说它就像同步代码一样。


如果你觉得本文对你有帮助,那就请分享给更多的朋友
关注「前端干货精选」加星星,每天都能获取前端干货
赞(0) 打赏
未经允许不得转载:WEB前端开发 » 用 async 和 await 编写现代 JavaScript 异步代码 – JavaScript 完全手册(2018版)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

前端开发相关广告投放 更专业 更精准

联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏