异步解决方案 async-await

3,144 阅读3分钟

异步解决方案—— Async/Await

异步操作是JavaScript编程的麻烦事,很多人认为async函数是异步编程的解决方案

Async/await介绍

  • async/await是写异步代码的新方式,优于回调函数和Promise。
  • async/await是基于Promise实现的,它不能用于普通的回调函数。
  • async/await与Promise一样,是非阻塞的。
  • async/await使得异步代码看起来像同步代码,再也没有回调函数。但是改变不了JS单线程、异步的本质。(异步代码同步化)

Async/await的使用规则

  • 凡是在前面添加了async的函数在执行后都会自动返回一个Promise对象

    async function test() {
        
    }
    
    let result = test()
    console.log(result)  //即便代码里test函数什么都没返回,我们依然打出了Promise对象
    
  • await必须在async函数里使用,不能单独使用

    async test() {
        let result = await Promise.resolve('success')
        console.log(result)
    }
    test()
    
  • await后面需要跟Promise对象,不然就没有意义,而且await后面的Promise对象不必写then,因为await的作用之一就是获取后面Promise对象成功状态传递出来的参数。

    function fn() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('success')
            })
        })
    }
    
    async test() {
        let result = await fn() //因为fn会返回一个Promise对象
        console.log(result)    //这里会打出Promise成功后传递过来的'success'
    }
    
    test()
    

Async/Await的用法

  • 使用await,函数必须用async标识
  • await后面跟的是一个Promise实例
function loadImg(src) {
   const promise = new Promise(function (resolve, reject) {
       const img = document.createElement('img')
       img.onload = function () {
           resolve(img)
       }
       img.onerror = function () {
           reject('图片加载失败')
       }
       img.src = src
   })
   return promise
}
const src1 = 'https://hcdn1.luffycity.com/static/frontend/index/banner@2x_1574647618.8112254.png'
const src2 = 'https://hcdn2.luffycity.com/media/frontend/index/%E7%94%BB%E6%9D%BF.png'
const load = async function () {
   const result1 = await loadImg(src1)
   console.log(result1)
   const result2 = await loadImg(src2)
   console.log(result2)
}
load()

当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。

async/await的错误处理

关于错误处理,如规则三所说,await可以直接获取到后面Promise成功状态传递的参数,但是却捕捉不到失败状态。在这里,我们通过给包裹await的async函数添加then/catch方法来解决,因为根据规则一,async函数本身就会返回一个Promise对象。

const load = async function () {
    try{
        const result1 = await loadImg(src1)
        console.log(result1)
        const result2 = await loadImg(src2)
        console.log(result2)
    }catch(err){
        console.log(err);
    }
}
load()

为什么Async/Await更好?

Async/Await较Promise有诸多好处,以下介绍其中三种优势:

  • 简洁

使用Async/Await明显节约了不少代码。我们不需要写.then,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量,还避免了嵌套代码。

  • 中间值

    在前端编程中,我们偶尔会遇到这样一个场景:我们需要发送多个请求,而后面请求的发送总是需要依赖上一个请求返回的数据。对于这个问题,我们既可以用的Promise的链式调用来解决,也可以用async/await来解决,然而后者会更简洁些

    const makeRequest = () => {
      return promise1()
        .then(value1 => {
          return promise2(value1)
            .then(value2 => {        
              return promise3(value1, value2)
            })
        })
    }
    

    使用async/await的话,代码会变得异常简单和直观

    const makeRequest = async () => {
      const value1 = await promise1()
      const value2 = await promise2(value1)
      return promise3(value1, value2)
    }
    
  • 提高可读性

    下面示例中,需要获取数据,然后根据返回数据决定是直接返回,还是继续获取更多的数据。

    const makeRequest = () => {
      return getJSON()
        .then(data => {
          if (data.needsAnotherRequest) {
            return makeAnotherRequest(data)
              .then(moreData => {
                console.log(moreData)
                return moreData
              })
          } else {
            console.log(data)
            return data
          }
        })
    }
    

    代码嵌套(6层)可读性较差,它们传达的意思只是需要将最终结果传递到最外层的Promise。使用async/await编写可以大大地提高可读性:

    const makeRequest = async () => {
      const data = await getJSON()
      if (data.needsAnotherRequest) {
        const moreData = await makeAnotherRequest(data);
        console.log(moreData)
        return moreData
      } else {
        console.log(data)
        return data    
      }
    }