# 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

# 支持

# 常见问题

# 参考

  1. 总结一下ES6/ES7中promise、generator和async/await中的异常捕获方法 (opens new window)
  2. 用 async 和 await 编写现代 JavaScript 异步代码 – JavaScript 完全手册(2018版) (opens new window)
  3. 细说 async/await 相较于 Promise 的优势 (opens new window)

# 总结

每一个特性的出现,总有它的用途,而只有用了,才能更好地理解它。

JavaScript的异步编写方式,从 回调函数 到 Promise、Generator 再到 Async/Await。表面上只是写法的变化,但本质上则是语言层的一次次抽象。让我们可以用更简单的方式实现同样的功能,而不需要去考虑代码是如何执行的。

换句话说就是:异步编程的最高境界,就是根本不用关心它是不是异步。