00:01
好,我们来看第十个例子,叫做promise,那么promise它是做什么的呢?它主要是解决异步编程的,呃一些呃回调函数,我们可以呢,用promise啊这样的一个解决方案来帮助我们完成啊这样的一些任务,那么promise呢,实际上是一个构造函数,在javascript当中,如果我们说它是一个构造函数的话啊,那么我们就可以用new来去调用它,就类似于咱们Java当中的创建一个对象,那实际上它也是一个函数啊,跟之前我们定义的各种各样类型的函数呢,都属于函数类型的,都属于函数类型的,只不过有的函数呢比较特殊,叫构造函数,那如果是构造函数的话呢,一般情况下这个定义的时候,当然这个是啊,Script底层定义的啊,好,就相当于我们Java的源码是那种东西哈,好,那这个是它底层定义的,那如果构造函数的话呢,就大写字母开头,所以看起来就像一个类似的是不是,嗯,但是它的本质却和咱们Java当中的类啊啊有非常大的不同啊好,那我们就。
01:01
就说到这这块,那我们现在呢,就把这个呃promise啊,这个构造函数呢,用它来创建一个对象啊,如果创建对象的话呢,那就是new promise了,好,那这个new promise有什么作用呢?我们来看后面呢,它整个是一个什么呀,整个是一个大括号,好我们呢,我我我我我来给大家写一下啊在这个地方。叫做。基本语法。好,那就像刚才我们描述的一样,这庞既然是个构造函数,所以呢,我们来创建它的时候呢,就通过这样的方式来创建啊,创建的时候呢,也是一样,把它定义给一个这个地方,我选择用常量定义哈P,好,因为后期我们也不想对它进行一个改变啊,所以呢,我就直接定义成那个Co类型的P了,好然后接下来呢,后面呢,它是一个函数类型的参数,而这个函数类型的参数呢,我们可以用刚才咱们刚刚学的这个箭头函数的形式来写好,这个就是promise的一个基本的用法,那么它是干什么用的?我们说它是解决异步编程的。
02:12
异步编程解决方案。那异步编程的话呢,在我们的前后端开发的过程当中呢,有一个很典型的,比如说前端调用后端的接口啊,这个后端的接口呢啊,相对于前端的脚本来说,它就是异步的啊,因为你从前端向后端如果发起阿贾克斯请求的话,那么后端呢,它要经过一一系列的处理,经过一段时间之后呢,才能够把真正的结果返回回来,这个就是异步编程的其中的啊一个使用场景,那另外呢,还有一个非常常见的异步编程的使用场景呢,就是文件的读取,好文件呢,因为是啊,一般情况下呢,如果我们有一个文件的话啊,有很多种存储方式,最典型的存储方式呢,就是存储在我们操作系统的磁盘当中,这样的话呢,我们就可以用,比如说在Java当中,我们可以用IO流的方式从我们的操作系统当中读取文件,那么因为IO流被从操作系统的磁盘当中读取到内存当中,它是有一定的时间延迟的,所以说文件读取的这样的一个操作。
03:16
后呢,也叫做异步编程啊,那我们的promise呢,也可以解决像这种文件的读取,还有什么阿贾克斯啊等等啊这种异步编程的场景,那我们呢,就以文件的读取为例,好,那怎么去读取一个本地文件呢?首先在no的JS这个环境下啊,它呢啊在原本的javascript基本功能的基础上呢,在noteva平台上呢,有一个扩展,这扩展叫什么呢?快。使用require去调用它的扩展,Iquqre啊,这是一个关键字,好使用require去调用扩展,怎么调用呢?这个扩展的名字呢,有很多note JS里面内置了非常多的扩展,比如说FS,就是文件系统扩展,通过这个扩展呢,我们可以去读取本地文件,那我在这个里面呢,给他。
04:08
定义到一个常量里面叫FS,好,那这块呢,就是引入我们的本地文件扩展块,引入no的GS中的本地文件扩展模块啊,好,那么这里面涉及到两个概念,第一个概念就是模块的名字,内置的啊,固定的就叫FS,第二个我们怎么样去把模块引进来,叫require啊,它有一点点类似于Java当中的import,相当于我引入一个啊这个其他包里面的这样的一个类,然后我好在当前的这个类当中呢,使用这个类下面的成员和方法对不对,那他这个块呢,也有点类似啊,就是我使用这个默认情况下,在当前的这个环境下呢,用不了的一些扩展,那我用块把它呢,从我们的呃这个。呃,Node JS平台当中的底层提供的这些扩展的库当中呢,把它获取出来,然后呢,定义到FS里面,好,然后接下来呢,我们就可以去读取这个文件了,那我们说呢,文件的读取它是异步的,所以呢,我们在读取文件的时候呢,就必须呢。
05:18
啊,有一个这个异步的解决方案,那这个异步的解决方案就是promise了,那我们把读文件的过程呢,放在这个大括号里啊,所以这边呢,我们开始实例化,实例化补招,每然后接下来呢,嗯,执行文件读取的异步操作,所有的异步操作我们要写在这个promise对象啊,这个声明的这个函数的后面的这个方法体当中啊,所以这块呢,是执行一系列的异步操作的位置,那这块呢,我们这样写,执行异步操作。
06:00
好,接下来呢,在这个地方我们有FS,就是刚才引进来的这个模块啊,FS这个模块里面呢,有一个叫做read file啊,这也是固定的一个方法啊,在FS这个模块当中自带的这么一个方法,相当于啊文件接口对吧?然后这个文件接口里面的接口方法啊,好,然后接下来呢,我们来读一个文件,这个文件呢,首先我们要写一个文件的一个相对路径,那当然了,我们可以把之前我们年前哈写的这个他点TST复制过来,我们就用它吧。好,那这个先。关一下啊,然后那这样的话呢,我们就写当前点杠。它点TST,好,这样的话呢,我就读取到这个文件了,然后因为读取文件的过程呢,它是一个异步的一个过程,所以呢,在这个过程当中呢,肯定有可能会读取成功,也有可能会读取失败,那这样的话呢,我们后面这块啊,又是一个参数,也就是说read file呢,它有两个参数,第一个参数呢,就是你读取的文件的路径啊好好,它还有第二个参数,第二个参数是什么呢?第二个参数呢是读取的过程,或者是说呢,读取啊过程当中对响应结果的处理。
07:29
读取过程中对响应结果的处理好,有什么样的结果呢?那肯定不是成功就是失败,所以呢,这里面呢,又是一个建筑函数。那很显然,读取文件的过程呢,整个是一个异步的,然后接下来呢,我们有两个结果,第一个结果呢,啊叫做失败,第二结果呢,叫做成功,那这两个参数,注意是这个read file这个函数自动注入进来的,也就是说你呢,无论给这两个参数起什么名字,比如说我取D,我取D,那它俩的意思都是一样的啊,名字不重要,位置很重要。
08:18
这个箭头函数里面的第一个参数,无论叫什么,它都表示的是当文件读取失败时。失败时的错误对象好,所以呢,If如果文件读取成功,这个错误对象呢,它就不存在,如果不存在的话呢,我们就说这个if表达式呢,它就为假啊,如果A不存在,我们说if表达式就为假,如果A存在,我们就说if表达式为真啊,所以说呢,如果errorr存在,那我们呢,可以在这个地方呢,去比如说cancel一下的cancel点。
09:04
Log啊,文见读取失败是不是啊,可以这样写啊,然后接下来呢,我们可以在这个地方呢,就return一下,好,这是文件读取失败的情况,那么如果文件啊这个。读取的过程当中没有,不过到L对象,那也就是说这个A表达式呢,就不会去走了啊,那他就直接跨过这个分支来走到后面的这行代码当中,那所以呢,我们可以在这个地方呢,看一看cancel.log,那这个data是什么呢?这个data呢就是文件的内容啊,当文件。读取成功时的文件内容啊,会放在这个贝塔里,所以呢,我们就把这个data塔呢,就可以给它打印出来了,那么接下来呢,我们来运行一下这个幺零,好大家看这个后面这块呢,其实就文件读取成功了啊,它的它的一个内容了,只不过它的这个表现形式呢,我们可能看起来。
10:16
嗯,对我们来说并不太友好是不是啊,所以那这怎么办呢?我们可以去,嗯,在这个地方给他进行一个突死,我看一下啊点死转让一下他突死顺方法。好,这样的话呢,我们就可以把这个文件的这个真正的内容以字符串的形式展示在我们的控制台当中了,所以呢,这个是我们异步编程,那跟promise有什么关系呢?注意到目前为止呢,还和这个没有什么关系,为什么,因为你看啊,我现在呢,把这句话呢,假设说我我把promise这个相关的代码先给它屏蔽掉哈,就这样是吧,FS read。
11:02
你看是不是一样的呀啊,然后文件读取失败的话,来一个他一好文件读取失败对不对,好像貌似跟promise没什么关系,那接下来我们来看一下promise他扮演一个什么角色,我把这个给它放开啊好,那promise扮演一个什么角色呢?在我们文件读取的过程当中,大家看这个地方呢,它的业务逻辑呢,其实啊,相对来说呢,比较处理的比较集中啊,你像这一部分呢,处理的是我们文件读取失败的业务逻辑,这一部分呢,是文件读取成功的业务逻辑,但是在实际开发的过程当中,我们肯定不能就这么草稿的梳理就结束了,有可能呢,这个整个的处理过程呢,都非常,呃,就是业务逻辑都非常多,所以呢,我们可能会把它们单独提取出来,放到另外的一个呃方法当中去处理,那么最简单的一个方式呢,实际上就是介入借助于promise的状态啊。
12:01
他对象有三个状态,好这三个状态呢,分别是初始化状态,还有成功以及失败,就这三个状态,那默认情况下呢,我们只要new了这个promise,我们说呢,这个,呃,整个的这个promise的对象的状态呢,就是初始化的状态了,好我们可以通过嗯,一个。叫做。内置的这么一个参数啊,这里面有两个内置参数,第一个呢叫so,第二个呢叫做好,这两个内置参数呢,是promise这个构造函数,它在定义这个。函数的参数的时候,自动帮我们注入进来的,这个reserve是什么呢?这个呢就是。
13:01
一个函数的引用,注意这里面是Java quick当中比较别扭的地方,大家一定要认真听啊,听不懂的话课后看这个视频,反反复复的多看几遍好,注意这个result是什么呢?是一个参数对吧?这个什么它也是一个参数,我们说这参数是什么数据类型呢?注意这个参数是函数数据类型的参数。啊,函数类型的参数什么意思呢?通过reserve函数,我们可以修改promise的状态,把promise的状态改成处理成功。好,第二个呢,就是这个。它也是一个函数类型的参数,那么同样它可以将promise状态设置为处理失败啊,啊所以说呢,这两个是函数啊是函数,那这个啊函数呢,那我们怎么去用呢?比如说在这个地方是当文件。
14:19
处理失败的时候,是不是或者说当文件读取失败的时候,那么当文件读取失败的时候呢,我们把原来的这个代码直接删掉,用什么呢?用这个呢,就是可以将promise的状态设置为失败,也就是说当文件读取失败的时候,我整个这个promise对象的状态就变为了失败状态。好,另外呢,它还可以接收参数,这参数呢,我们可以直接把当前的这个错误对象传递给啊传递给他,好,那这个是当文件处理失败的时候,那么当文件读取成功的时候呢,我们说我们可以把这个。Promise的状态呢,设置为成功的状态,所以呢,我们就可以在这个地方写。
15:05
把data呢,作为这个reserve函数的参数呢传进去,好,到这为止它会发生什么呢?我们来看一下啊。好,好像貌似什么都没发生,只不过这个地方呢,报了一个错,那没有这个目录或者是文件,也就是说这个地方很显然他是走了处理失败啊这样的逻辑,然后接下来呢,我再把这个文件名呢给他啊改修改正确再读,那很显然呢,他就没有报告上面的错误,就说明呢,我们这个里面什么事都没有发生啊,没有消息就是好消息,对不对,没有发生错误,那但是这个reject和resolve它有什么作用呢?我们通过reject方法去将pro的状态改为失败,或者是说通过reserve方法将promise状态改为成功。
16:02
之后我们接下来要做什么呢?我们接下来要做的就是当promise的状态为失败的时候,我们调用一段失败的专门的业务逻辑,当promise的状态为成功的时候,我们调用一段成功的专门的业务逻辑,那这个业务逻辑呢,我们可以专门的写在这样的一个代码段里,就是P,因为刚才呢,通过调用它或者是它,我们实际上设置的是谁的状态,设置的是它的状态,而它呢,有两个方法,一个呢是then,当promise的状态为成功的时候,那么问方法会被调用啊,还有一个方法呢,叫做p.catch当promise的状态。当promise对象的状态为失败的时候,那么这个catch方法会被调用。当promise的状态。
17:02
成功时。Then调用当每的状态,如失败态对要用好,那怎么写呢?P点的好这里面呢,又是一个箭头函数,当promise的状态被改为成功的时候,我们可以把data塔传递到reserve这个函数当中,那么在when这个地方。它就可以把data里面传递的这个内容啊给它取出来,比如说你这个地方也写data啊,它俩表示的是同一个东西,通过这个地方是不是promise的状态修改为成功嘛,修改成功的时候问不就被调用了嘛,所以这个代码一执行,这个代码立即被执行,而这个代码当中传进来的参数立即被这个代码当中的问方法的箭头函数的参数所调用啊明白这意思吧?问方法里面也有一个箭头函数,它是一个回调,回调里面呢有一个内置的自动注入的参数,这个参数是什么呢?就是这个贝塔,当然这参数的名字你写什么就行,写data塔也行啊,传统呃来说的话,我们愿意写response叫响应对不对?好,然后接下来呢,我可以在这个地方去打印我的题习can松点是放点好,相当于原来我们在这个地方写data塔好。
18:36
然后接下来呢,我们来运行一下。这是邓哈。Response,这写错了啊,Response好,然后运行一下,好大家看是不是这首诗就打印出来了呀,啊,这个是啊,我们再走一遍这个流程啊,这个流程是这样的啊,首先呢,我们去获取一个文件扩展对象,然后接下来呢,我们创建一个promise对象,好promise对象被创建出来之后呢,它默认的状态呢,就是初始化状态,接下来呢,在这个里面呢,我们用FS去,呃,调用我们本地的一个文件,然后呢去把这个文件读取出来,读取出来的时候呢,我们有两种结果,一种结果呢是失败,一种结果呢是成功,那我们先来看,如果文件读取没有失败,那么它要势必会走到这个代码,那么如果文件读取成功了,那我们就把当前的promise的这个对象的状态呀,先设置为什么呀,设置为成功状态啊,那一旦promise的对象变为成功状态,后面的这个嫩方法就会自动的被调用,所以呢,当我们的代码段走到这的时候,实际上呢,它会自动的被。
19:42
啊,调用到这个二十五行里面的这个代码块当中来,而二十五行里面的这个代码块后面的箭头函数里面所接收的response呢,就是你刚才在这个地方传递的data,所以说通过这种形式呢,我们就把整个的成功处理业务的逻辑和真正读取文件的过程,就把这两个业务给他独立出来了,那所以我们的应用程序的结构呢,就更清晰了啊,那避免了我们把这一段的代码大量的嵌套在这个read file的这这个它的这个代码块里面,这样的话,业务逻辑呢,都混在一起,代码的可读性呢,不是特别高啊,所以这个是处理我们的成功的业务逻辑,那另外呢,我们还可以处理失败的业务逻辑啊,处理失败的业务逻辑呢,就是p.catch。
20:27
然后这块呢,嗯,也是一样的,我们可以写ER or啊,或者是像这个一样写ER都行啊,这个地方的变呢,你自己随便命名,但是无论你怎么命名,因为它是内部自动被注入进来的,它表示的是什么呀?就是当时当文件读取失败的时候,我们在这个地方呢,将promise的状态改为失败,改为失败之后呢,给它传了一个参数,那么此时此刻怎么怎么样呢?如果promise的状态为失败时,是不是K会被调用啊,所以这个地方呢,就会自动的调用catch,好,那我们这个地方呢,比如说我可以写ER or啊,不一定非要和这个地方一样啊,好,那它就可以把这个地方的A对象呢接收到这块来,那所以呢,我们就可以在这地方呢,去通过箭头函数来打印这个IO对象,比如说pencilo.log。
21:19
嗯,出for了是吧,然后接下来呢,我们再改一下pencil.lo ER or好,然后我们来看一下出错的一个情况,那这个地方我们写一好,那这个地方呢,我们嗯,CTRL加波浪线啊,把这个命令行给它打开,然后接下来呢,No的幺零推车,大家看是不是出错了啊好,然后接下来紧接着跟着出错了,就是一个L对象,好,所以下面这块呢,实际上就是I对象的一个输出的这样的一个完整的流程,然后呢,他说LL码错码四负的4058啊,然后加来呢,呃,路径就是这个啊,他说这个呢,实际上是路径不存在,你看。
22:08
No such fair dictionary,对不对?嗯,这路径是不存在的,好,所以这块呢,就是打印了一个错误的对象啊,那同时呢,这个then也好,这个catch也好,它本身返回的也是一个P对象,所以如果这个方法和这个catch方catch方法也返回它自己的话,那么我们就可以这样用串联的方式去写。啊,用串联的方式去写,那这样的话呢,这个里面处理的是成功业务逻辑。这里面处理的是失败业务逻辑,所以我们的代码呢,就天然的分成了三个部分的逻辑区域,那么第一个逻辑区域呢,就是读文件的过程。啊,并且创建出来第二个过程呢,就根据promise的状态,然后我们呢,去处理不同的业务啊第一个业务呢,就是当promise的状态为什么的时候呢?当promise的状态为成功时,对吧?啊也就是说当调用reserve时,那么我们走问这一句话啊第二个catch呢,就是当promise的状态为失败时,也就是说如果前面走了if语句调用了reject,那么reject呢,将promise的状态修改了,那一旦失败我们就直接走开,所以这个整个就是我们的应用程序的一个promise的一个使用,那它呢,虽然比最开始我们写的那个方法要复杂一些,但是呢,它却可以很好的在特别代码量特别大的情况下,帮助我们做业务逻辑的一个代码划分啊,这样的话,代码的可能量呢是比较高的,所以呢,这块是我们的promise的一个基本的用法啊,那像这种promise的用法呢,在我们的项目当中也非常重要啊,所以这块代码大家要读。
23:56
动,然后后面呢,大量的我们都会使用这个promise来完成我们一些非常重要的工作的开发,比如说前后端分离当中的接口调用部分,我们一律都会使用类似于这样的代码段啊来进行编写。
我来说两句