javascript之异步函数
这篇文章详细讲解了JavaScript中的异步函数。 JavaScript中的异步代码在很短的时间内从回调发展为Promise,再到ES2017的异步函数,现在我们可以像编写同步代码那样编写基于 Promise 的代码,而且还不会阻塞主线程。
为什么需要async/await?
当promise在ES2015中引入时,目的是解决异步代码的问题,但是promise不是最终的解决方案。
虽然Promise解决了著名的回调地狱,但是它自己引入了语法复杂性。
所以ES2017增加了异步函数,提高了代码可读性,对不太熟悉 Promise 的人而言,帮助就更大了。
async/await使代码看起来像是同步的,但它在后台是异步和非阻塞的。
工作原理
异步函数返回一个promise,如下例所示:
const doSomethingAsync = () => { return new Promise((resolve) => { setTimeout(() => resolve('I did something'), 3000) }) }
调用一个异步函数时,您先要设置一个await,当您 await 某个 Promise 时,函数暂停执行,直至该 Promise 产生结果,并且暂停并不会阻塞主线程。 如果 Promise 执行,则会返回值。 如果 Promise 拒绝,则会抛出拒绝的值。因为异步函数去掉了所有回调。提高了代码的可读性,这是一个例子:
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 //after 3s I did something
Promise详解
将async关键字添加到任何函数意味着该函数将返回一个promise。即使它没有声明,它也会在内部使它返回一个promise。
这就是此代码有效的原因:
const aFunction = async () => { return 'test' } // This will alert 'test' aFunction().then(alert)
它和以下一样:
const aFunction = async () => { return Promise.resolve('test') } // This will alert 'test' aFunction().then(alert)
代码更易读
正如上面示例所见,与回调和promise代码相比,异步函数代码看起来非常简单。
我们下面用更复杂一点的代码来演示。
例如,以下是使用promises获取JSON资源并解析它的方法:
const getFirstUserData = () => { // get users list return fetch('/users.json') // parse JSON .then(response => response.json()) // pick first user .then(users => users[0]) // get user data .then(user => fetch(`/users/${user.name}`)) // parse JSON .then(userResponse => response.json()) } getFirstUserData()
以下是使用await / async提供的相同功能:
const getFirstUserData = async () => { // get users list const response = await fetch('/users.json') // parse JSON const users = await response.json() // pick first user const user = users[0] // get user data const userResponse = await fetch(`/users/${user.name}`) // parse JSON const userData = await user.json() return userData } getFirstUserData()
链接多个异步函数
异步函数可以非常容易地链接,并且语法比简单的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使得这非常简单,因为就像调试同步代码一样。