ES7中【async...await...】讲解

上一章我们说过了Promise,其实使用上已经足够。就是在理解上,还需要自己多动手敲一些代码;今天来说说另一个异步请求,是ES7中的新方法async...await...

那么我们知道了异步请求的优势,也知道可以使用回调函数或者更好的方法Promise来处理异步,那么为什么还要有引入新的异步方法?

答案是Promise也有缺点:
首先Promise的代码还达不到很简洁的程度(如果有太复杂的异步,代码也会很复杂,可读性不高);
其次不能像同步代码一样方便获取到错误信息;

那么async/await怎么用,我们从字面意思理解:async:异步;await:等待

async 是异步的意思,是一个关键字,将 async 关键字放在函数前边,表示某个函数就是一个异步函数,这样就不会影响下边线程的执行顺序,那么为什么有这个关键字就会变成异步请求?我们打印一下带有关键字的函数看一下:

async function foo(n){
    return n
  }
console.log(foo(222))

控制台会打印出这样:

ES7中【async...await...】讲解

会神奇的发现,打印出来的是一个带有Promise对象,并且resolved完成状态,结果返回了222。

所以,async函数是包装成了Promise对象作为的返回值 => Promise.resolve(value)

await是等待的意思,放在要异步操作的方法前边。在异步函数当中,等待一段要发生的代码,返回后再向下执行,在没返回值之前,当前异步函数中await后的代码暂不执行。我们看两个重要的例子,仔细看一下

// 随便写一个延迟函数
function result() {
    setTimeout(() => {
        console.log('异步请求')
    }, 2000);
}

// 然后使用这个方法,先用一个await
async function foo(){
    console.log('111')
    await result();
    console.log('222');
  }
foo()
console.log('333')

ES7中【async...await...】讲解

打印结果如上,函数照常执行,所以先打印了111,然后遇到了await等待关键字,发起了异步请求,所以222是在333之后打印的,在等待2秒之后,最后打印出“异步请求”。

那么如果我把await关键字去掉会怎么样?

// 随便写一个延迟函数
function result() {
    setTimeout(() => {
        console.log('异步请求')
    }, 2000);
}

// 然后使用这个方法,先用一个await
async function foo(){
    console.log('111')
    result();
    console.log('222');
  }
foo()
console.log('333')

结果是:

ES7中【async...await...】讲解

可以看出,222不再受到await影响,按照了111、222、333正常打印。

问题来了:

  1. 那await加与不加有什么用呢?2秒钟后不都可以打印出“异步请求”四个字吗?
  2. 上边所说的 “ 在异步函数当中,await等待一段要发生的代码,返回后再向下执行,在没返回值之前,当前异步函数中await后的代码暂不执行 ” 这句话也没有得到验证,222照常打印出来,又是什么原因?

原因请注意上述代码,result函数并不是异步函数,仅仅只是个带有延迟的函数,如果我更改一个result函数,加上Promise,使它成为一个异步函数,我们再来看一下:

// 此刻我们写一个异步方法
function result() {
    return new Promise((resolved,reject)=>{
        setTimeout(() => {
            resolved(console.log('异步请求'))
        }, 2000);
    })
}

// 然后使用这个方法,需要用到await
async function foo(){
    console.log('111')
    await result();
    console.log('222');
  }
foo()
console.log('333')

打印结果如下:

ES7中【async...await...】讲解

先打印出111和333,2秒钟过后,打印出“异步请求”和222,所以这也是证明了 async/await 是操作异步方法,在返回结果之前,await后的代码,是不执行的。

async/await可以捕获到错误信息,利用try...catch,只需要在要捕获的地方加上这个方法即可:

function result() {
    return new Promise((resolved,reject)=>{
        setTimeout(() => {
            reject(console.log('异步请求'))
        }, 2000);
    })
}

// 然后使用这个方法,需要用到await
async function foo(){
    console.log('111')
    try{
        await result();
        console.log('222');
    }catch(err){
        console.log(err)
    }
  }
foo()
console.log('333')

ES7中【async...await...】讲解

上边的undefined就是错误信息,只不过这个案例没有错误信息;在实际项目中,有一些错误,我们就可以用这种方式捕获到错误信息,(try...catch语句用于处理代码中可能出现的错误信息),如果用在Promise当中,捕获错误信息就会很麻烦。这也是async的一个优点。

这样看起来 async/await 的写法,很像同步的写法,但是却可以像Promise一样去处理异步,这就是一种代码简洁的好处,如果有多个异步需要处理,不再需要像Promise那样很多 .then 代码横向发展,我们来做一下对比,例如有ABCD四个异步需要触发:
Promise写法

const result = () => {
  return aaa()
    .then(() => A())
    .then(() => B())
    .then(() => C())
    .then(() => D())
}

result()
  .catch(err => {
    console.log(err);
  })

async/await写法

const result = async () => {
  await A()
  await B()
  await C()
  await D()
}

result()
  .catch(err => {
    console.log(err);
  })

上述的代码,只是为了证明async/await写法的可读性会更好,我们在写项目时,在返回的结果中会做很多处理,这种写法在多层嵌套中,你就会发觉它的优势了。

以上就是简单介绍关于async/await的用法,还有很多的用法,例如取中间值,All方法等等,同学们可以进一步去查阅资料,在实际项目中,掌握以上的关键的知识点,是必要的。

有兴趣的同学也可以查询async/await的原理,包括进一步学习关于generator函数,并且可以在评论区留言,共同进步。

weChat:VillinWeChat

欢迎提出宝贵意见

上一篇:Vue 中 $nextTick() 讲解


下一篇:【CSS】思考和再学习——关于CSS中浮动和定位对元素宽度/外边距/其他元素所占空间的影响