- 前言
- 关于 ECMASCRIPT 发展史和现状
- ES6 带来的重大特性
- ES2016(ES7)的改进
- ES2017(ES8)带来的重大新特性
- ES2018(ES9)带来的重大新特性
- JavaScript 编码风格指南
- JavaScript 词法结构(构建块)
- JavaScript 变量
- JavaScript 数据类型
- JavaScript 表达式
- 原型继承
- 如何使用 JavaScript 中的 Classes(类)
- JavaScript 异常处理
- JavaScript 中的分号(;)
- JavaScript 中的引号
- JavaScript 字面量模板(Template Literals)指南
- JavaScript 中的 function(函数)
- JavaScript 箭头函数(Arrow Function)
- JavaScript 中的闭包(Closures)
- JavaScript 数组(Arrays)
- JavaScript 中的循环(Loops)
- JavaScript 中的事件(Events)
- JavaScript 中的事件循环(Event Loop)
- JavaScript 异步编程和回调
- 理解 JavaScript 中的 Promises
- 用 async 和 await 编写现代 JavaScript 异步代码
- JavaScript 中的 循环(Loops) 和 作用域(Scope)
- JavaScript 定时器 setTimeout() 和 setInterval()
- JavaScript 中的 this
- JavaScript 严格模式(Strict Mode)
- JavaScript 中的 立即执行函数表达式(IIFE)
- JavaScript 中的数学运算符
- JavaScript 中的 Math 对象
- 介绍 ES Modules(模块)
- 介绍 CommonJS
- JavaScript 术语表
用 async 和 await 编写现代 JavaScript 异步代码
现在,我们将探索 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 使得调试非常简单,因为对编译器来说它就像同步代码一样。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论