JavaScript异步编程:Async、await与Promise

目录

参考博文:

摘要:

一、异步的概念:

二、setTimeout实现复杂异步编程:

三、Promise实现复杂的异步编程:

四、异步函数“Async Await”:

1、async关键字:

2、await关键字:

await的返回值:

3、“async await”实现复杂异步编程:

4、异步函数异常处理机制:


参考博文:

        这篇文章是本人查了不少资料,以及相关博主的文章之后的归纳总结。尤其是以下这篇大佬博文:大佬博文

摘要:

        本文按照一下的顺序来进行行文,可以这样更有有利于去理解各个部分想要表达的含义、效果,更加容易掌握JavaScript异步编程。

  1. 首先介绍了什么是异步编程,什么时候需要使用异步编程来实现对应的功能需求。
  2. 其次尝试使用定时器setTimeout来实现异步编程,并且暴露出这种方式在复杂异步编程时候的缺点:代码的嵌套层次太多、可读性差、代码不易维护。
  3. 然后在使用setTimeout的基础上再使用Promise来实现异步编程,使用Promise的主要目的是:更优雅的写复杂的异步任务。即将复杂的异步编程由“嵌套格式”转换成“顺序格式”
  4. 最后引入异步函数,“async await”的使用。即使使用了Promise异步编程可以转换成“顺序格式”,但是代码的可读性依然比较差。引入“异步函数”之后,通过使用“async await”可以是代码结构清晰、可读性较高。

        如果不了解什么是定时器的,可以参考了解JavaScript定时器。如果对Promise不了解的,可以参考JavaScript(菜鸟教程)Promise对象(ECMAS6入门)

一、异步的概念:

        异步与同步是相对的概念。在我们学习的传统单线程编程中,程序的运行是同步的(同步并不是所有步骤同时运行,而是指所有的步骤按照指定的顺序执行)。而异步的概念则是不保证同步的概念,也就是说一个异步过程的执行不再与原有的序列有顺序关系。

        异步就是从主线程发射一个子线程来完成任务,不按照代码顺序执行,效率更高。

什么时候使用异步编程?

        在处理一些简单,快速的操作的时候,一般在主线程中是完全可以解决的。主线程作为一个线程,不能同时接受多方面的请求。所以当一个事件、任务没有结束之前,主线程是无法响应其它请求的。

        假设在网页设计中,如果点击一个按钮会造成死循环,那么当按下这个按钮之后整个界面将卡死而无法接受其它响应。为了避免这种情况发生,通常我们会使用子线程来完成一些耗时较长的任务,比如大文件的读取,网络请求的发送。游戏子线程是独立于主线程的,所以即使子线程出现了阻塞也不会影响主线程的运行。

        但是子线程有一定的局限性:子线程和主线程之间的关系是异步的,即子线程与主线程失去了同步关系。我们无法确定子线程的结果,因此无法对其做出相应的响应。为了解决这个问题,JavaScript中的异步操作函数是通过回调函数来实现异步任务的处理结果。这样一来主线程就不用再关心异步子线程的任务状态。

二、setTimeout实现复杂异步编程:

        假设当前有以下情形:分三次输出字符串,第一次间隔1秒,第二次间隔4秒,第三次间隔3秒。那么如果使用setTimeout实现如下:

        这段代码虽然实现了功能,但是却使用了复杂的嵌套结构,使代码的具有了一定的复杂性,可读性和后期的维护都是不方便的。

三、Promise实现复杂的异步编程:

        在上述使用setTimeout的基础上再使用Promise的目的是抛弃复杂的嵌套层次,将复杂的异步编程由“嵌套格式”转换成“顺序格式”。

        对于上述代码内容,我需要做以下讲解,希望可以提高大家的对这段内容的理解程度,因为我才开始接触的时候也是比较迷糊的。

  1. 首先,你一定要了解、知道Promise是什么、大概怎么用的。Promise创建时的参数意义、resolve()方法、reject()方法;Promise对象的.then()、.catch()、.finally()等方法。
  2. 其次,这段代码不要认为还是嵌套结构,这是一个顺序结构。

代码运行流程:

  1. 创建一个Promise对象,立刻执行对应的回调函数。定时器1秒延时结束之后输出“First”,并且通过resolve()设置运行结果,这样下一个then()函数才会正常的运行。
  2. 第一个then函数接收到了返回结果之后,执行对应的回调函数体。新建了一个Promise对象,立刻执行对应的回调函数。当定时器4秒延时结束之后,输出“Second”,并且通过resolve()函数设置该Promise对象的运行结果,这样第二个then()函数在接收到结果之后才能正常运行。
  3. 第二个then函数接收到了新建的Promise对象的返回结果,然后执行对应的回调函数。输出“Third”。
  4. 注意:要知道上述的then()函数对应的Promise对象到底是哪一个。

四、异步函数“Async Await”:

        上述通过Promise已经可以将复杂的异步编程由“嵌套结构”转换成“顺序结构”。但是代码的可读性依然是比较低的,代码的结构不够清晰。 “async await”它是基于Promise的,这是ES6新增的。为了解决大量复杂不易读的Promise异步的问题才应运而生的。

1、async关键字:

        关键字“async”必须声明的是一个函数function,表示“异步函数”。“async”是异步的意思,该关键字声明的异步函数,异步函数的返回值是一个Promise对象。

         对于上述异步函数的返回值是一个Promise对象,在此例中该对象的状态是“fulfilled”,并且已经拿到了返回值为“Promise返回值”。对于上述的return语句的等价关系我们可以通过下面的示例来进行验证:

2、await关键字:

        “await”关键字必须在使用“async”声明的异步函数的内部使用,并且必须是直系的

        阮一峰老师说:“async函数返回一个Promise对象,当函数执行的时候,一旦遇到await就会先返回,等到触发的异步操作完成,再接着执行函数体后面的语句。”那么代码是这样运行的吗?我们下面来测试一下:

       ???为什么先输出的下面然后才输出的定时器异步回调呢?那是因为await阻塞等待是有条件的:“如果await后面是Promise对象,会将Promise异步操作转换为同步,线程阻塞等待Promise的resolve/reject返回结果之后,再执行函数体内后面的语句!” 我们继续测试:

        怎么有不对呢?下面的函数体部分竟然没有执行?因为:“如果await后面是一个Promise对象,那么需要等待这个Promise对象解析完成,如果没有收到resolve或reject函数的返回结果,后面的函数体部分就不会执行。” 因此,请看下面这段代码:

         此时,就和阮老师说的一致了。因此,我们可以得到一下结论:“如果await后面不是一个Promise对象,那么代码就按照正常的JavaScript顺序执行:先执行同步代码,当主线程空闲了,再去执行异步队列的任务。如果await后面是一个Promise对象,那么线程就会阻塞等待该异步任务完成,并且接受到了Promise对象的返回结果之后才会执行函数体后面部分的代码段。”这个地方,如果对JavaScript的运行机制不太清楚的话,可以参考一下这里:JavaScript运行机制

await的返回值:

        从上面的例子可以发现:“await的后面如果是Promise对象,那么await的返回值就是Promise对象的resolve/reject返回结果。” 其实,这个地方在讲述“async关键字”的时候就已经可以看出来了,只是await关键字在这个基础上起到了阻塞等待的作用。

3、“async await”实现复杂异步编程:

        “async await”是在Promise的基础上发展而来的,是Promise的进化版。“async await”相比于“Promise”的优势在于它的then链,这样便可以不必将回调写在.then()函数内部进行嵌套,只需要使用await即可

        下面我们以这个例子来看看“async await”相比于“Promise”的优异性。依然是这个情形:分三次输出字符串,第一次间隔1秒,第二次间隔4秒,第三次间隔3秒。

 

        从上述两张图片的对比我们就可以看出来,使用“async awit”异步函数的形式会使复杂的异步编程变得和同步一样简单。异步函数中可以使用await指令,await后面必须跟着一个Promise对象。异步函数会在Promise运行中暂停,知道其运行结束之后继续运行函数体后面的代码段。

4、异步函数异常处理机制:

        这部分内容暂时不想写,因为我不想写。

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值