# async/await总结
# 说明
一句话解释:async 函数,就是 Generator 函数的语法糖。
- 建立在 promise 之上。所以,不能把它和回调函数搭配使用。但它会声明一个异步函数,并隐式地返回一个Promise。因此可以直接return变量,无需使用 Promise.resolve 进行转换。
- 和 promise 一样,是非阻塞的。但不用写 then 及其回调函数,这减少代码行数,也避免了代码嵌套。而且,所有异步调用,可以写在同一个代码块中,无需定义多余的中间变量。
- 它的最大价值在于,可以使异步代码,在形式上,更接近于同步代码。
- 它总是与 await 一起使用的。并且,await 只能在 async 函数体内。
- await 是个运算符,用于组成表达式,它会阻塞后面的代码。如果等到的是 Promise 对象,则得到其 resolve 值。否则,会得到一个表达式的运算结果。
# 开始
# 一个简单的例子
JavaScript 代码:
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')
# 一切都是 promise
将async
关键字添加到任何函数,意味着该函数将返回一个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'
# 代码更易于阅读 (重点看这个Demo)
每一个步骤都需要之前每个步骤的结果。
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()
并且与下面的代码等价:
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(异步) 函数
每一个步骤都需要之前每个步骤的结果。
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
# 2020更好的错误处理
// 这里使用了一个工具函数 handle,如此就可以避免 Unhandled promise rejection 报错,还能细粒度的处理错误。
const handle = (promise) => {
return promise
.then(data => ([data, undefined]))
.catch(error => Promise.resolve([undefined, error]));
}
async function userProfile() {
let [user, userErr] = await handle(getUser());
if(userErr) throw new Error('Could not fetch user details');
let [friendsOfUser, friendErr] = await handle(
getFriendsOfUser(userId)
);
if(friendErr) throw new Error('Could not fetch user\'s friends');
let [posts, postErr] = await handle(getUsersPosts(userId));
if(postErr) throw new Error('Could not fetch user\'s posts');
showUserProfilePage(user, friendsOfUser, posts);
}
# async/await中的错误处理
# async常用异常处理
async function error() {
try{
//do something
}catch(err){
console.log(err)
}
}
# async中的错误处理
因为async的返回值也是个promise,跟promise的错误处理差不多。此外,async里面throw Error 相当于返回Promise.reject。
async function F(){
throw new Error('test1')
}
var f=F();
f.catch(function(e){console.log(e)});
// Error:test1
# await中的错误处理
在async中,await的错误相当于Promise.reject。
async function F(){
await Promise.reject('Error test1').catch(function(e){
console.log(e)
})
}
var f=F(); // Error:test1
# await中的promise.reject必须要被捕获
await如果返回的是reject状态的promise,如果不被捕获,就会中断async函数的执行。
async function F(){
await Promise.reject('Error test1');
await 2
}
var f=F()
上述代码中,前面的Promise.reject没有被捕获,所以不会执行await 2
# 支持
# 常见问题
# 参考
- 总结一下ES6/ES7中promise、generator和async/await中的异常捕获方法 (opens new window)
- 用 async 和 await 编写现代 JavaScript 异步代码 – JavaScript 完全手册(2018版) (opens new window)
- 细说 async/await 相较于 Promise 的优势 (opens new window)
# 总结
每一个特性的出现,总有它的用途,而只有用了,才能更好地理解它。
JavaScript的异步编写方式,从 回调函数 到 Promise、Generator 再到 Async/Await。表面上只是写法的变化,但本质上则是语言层的一次次抽象。让我们可以用更简单的方式实现同样的功能,而不需要去考虑代码是如何执行的。
换句话说就是:异步编程的最高境界,就是根本不用关心它是不是异步。