这篇文章详细讲解了JavaScript中的异步函数。 JavaScript中的异步代码在很短的时间内从回调发展为Promise,再到ES2017的异步函数,如今咱们能够像编写同步代码那样编写基于 Promise 的代码,并且还不会阻塞主线程。javascript
当promise在ES2015中引入时,目的是解决异步代码的问题,可是promise不是最终的解决方案。java
虽然Promise解决了著名的回调地狱,可是它本身引入了语法复杂性。json
因此ES2017增长了异步函数,提升了代码可读性,对不太熟悉 Promise 的人而言,帮助就更大了。promise
async/await使代码看起来像是同步的,但它在后台是异步和非阻塞的。异步
异步函数返回一个promise,以下例所示:async
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的简单示例:fetch
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')
复制代码
上面代码执行结果以下:ui
Before
After
//after 3s
I did something
复制代码
将async关键字添加到任何函数意味着该函数将返回一个promise。即便它没有声明,它也会在内部使它返回一个promise。 这就是此代码有效的缘由:spa
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很难,由于调试器不会debug异步代码。 Async / await使得这很是简单,由于编译器就像同步代码同样。