JavaScript异步(必考三座大山之三)——第四集:async-await

前言

现在使用JavaScript开发的异步编程,基本上被async-await承包了,所以这个东西你不能不会。

第三集我们讲解到,要想解决异步的回调地狱,可以使用Promise对象里面内置的方法then,catch来解决回调地狱的问题,但是也是基于回调函数,但是我们接下来要学习的async-await是同步语法,可以彻底消灭回调函数。

语法介绍

在介绍语法之前,我们先对比两组代码:

1.使用Promise进行图片加载:

function loadImg(src) {
    const p = new Promise(
        (resolve, reject) => {
            const img = document.createElement('img');
            img.onload = () => {
                resolve(img);
            }
            img.onerror = () => {
                const err = new Error(`图片加载失败 ${src}`);
                reject(err);
            }
            img.src = src;
        })
    return p;
}
const url = 'https://class.imooc.com/static/module/marketpage2020/img/banner-icon-level0.png?t=2'
 
loadImg(url).then(
    img => {
        console.log(img.width);
        return img;
    }).then(
        img => {
        console.log(img.height); 
    }).catch(ex => console.error(ex));

2.使用async-await语法进行图片加载

function loadImg(src) {
            const p = new Promise(
                (resolve, reject) => {
                    const img = document.createElement('img');
                    img.onload = () => {
                        resolve(img);
                    }
                    img.onerror = () => {
                        const err = new Error(`图片加载失败 ${src}`);
                        reject(err);
                    }
                    img.src = src;
                })
            return p;
        }
        const url = 'https://class.imooc.com/static/module/marketpage2020/img/banner-icon-level0.png?t=2'

        const fn = async () => {
            const img1 = await loadImg(url)
            console.log(img1.width, img1.height);
        }
        fn();

执行结果是一样的,在这里就不加以展示了,代码1如果有同学看不明白的话,就到我们异步的第三集看看,知识点详细有写。

我们重点讲一下代码2:

执行过程:

1.首先我们定义了一个loadImg()函数包裹着一个新的Promise对象来加载图片。

2.其次定义了一个url常量存放图片地址

3.定义一个fn常量接收一个箭头函数,在箭头函数前面写上async关键字,因为执行await函数一定要有async关键字包裹,如果直接执行await函数就会报错

4.调用fn函数

执行结果分析:

上述的async-await语法,是使用同步的写法执行异步的代码的一种方式,很大程度上精简了代码,它是消灭异步回调的终极武器,是妥妥的香香甜甜的语法糖

async-await和Promise的关系

async/await虽然是消灭异步回调的终极武器,但是并不是跟Promise水火不相容的,相反,两者是相辅相成。

先简单介绍一下他们的关系:

1.执行async函数,返回的是Promise对象

2.await相对于Promise的then

3.try...catch可捕获异常,代替了Promise的catch

验证第一条:

fn1 = async ()=>{return "suc"}
console.log(fn1());

 虽然我们没有声明任何Promise,但是它‘suc’这个值封装成一个Promise对象,并且返回。相当于: return Promise.resolve('suc');

验证第二条:

 const fn2 = async ()=>{
       const p1 = Promise.resolve('CSND');
       const temp1 = await p1; 
       console.log(temp1);
}
const fn3 = async ()=>{
      const temp2 = await 'csnd';
      console.log(temp2);
}
fn2();
fn3();

 由此可见:await相当于Promise的内置方法then,await 'csnd'相当于Promise.resolve('csnd')

 验证第三条:

const fn4 = async ()=>{
      const p2 = Promise.reject('err1');
      try{
         const res = await p2
         }
         catch(ex){
             console.log(ex);
         }
}
fn4();

 async语法捕获错误,我们可以通过try..catch的方法来捕获,相当于Promise的内置方法catch。

异步的本质

其实归根结底,async-await只是一个很好用的语法糖,虽说它是消灭异步回调的终极武器,但是JS是单线程,还得需要异步,还得基于event loop机制。

我们拿一串代码唠一下就会明白了。

const fn1 = async () => {
      console.log('A')
      await fn2()
      console.log('B')
      await fn3()
      console.log('C')
}
function fn2() {
      console.log('D')
}
function fn3() {
      console.log('E')
}
console.log('F')
fn1();
console.log('G')

执行步骤:

1.前面定义的那几个函数肯定不会执行,因为还没有调用,所以第一个打印:F

2.调用fn1()函数,执行第二行代码,打印:A

3.调用fn2()函数,打印:D

4.执行完fn2()函数以后还没完,我们还需要执行前面的await操作。这里要敲黑板注意了:await的后面,都需要看作是异步的代码,简单来说,就是把await后面的代码封装成一个函数,然后丢给一个setTimeout函数里面,当成异步代码块去执行。所以执行同步代码,打印:G

5.同步代码执行完,启动event loop机制,按照执行顺序,打印:B

6.调用fn3()函数,打印:E(在这里给大家说一下,如果await 一个函数,先执行函数,再去执行前面的await操作)

7.打印:C

如果Promise,event loop 或者 异步概念依然比较迷茫的同学,可以翻看一下前面的内容。

创作不易,觉得笔者写得好的话希望大家点点赞和关注,今天就到这里。

猜你喜欢

转载自blog.csdn.net/weixin_50602266/article/details/121617460