00:00
好,那么接着呢,我们继续来看关于异步的操作,因为前面呢,我们讲过关于promised.Z的用法,以及a think of it和我们使用generator来去封装的异步操作,那这些呢,其实你会发现都是依赖于我们的promise来去实现的,那么对于promise的核心原理呢,我们也都比较清楚了,是promise,它本身呢就是一个承诺的含义,你去new呢,得到一个对象,它就会去帮你执行这个异步,异步的相关操作,那么它呢还有三个状态,就是在执行的过程中呢,会有一个pending的等待状态,那如果是异步执行结束之后呢,就会有一个成功或者是失败的状态,那么不管是成功还是失败呢,都会对应着不同的操作。
01:01
那所以根据这些基本原理,我们呢,其实也可以通过手写promise源码的方式来去更加深刻的理解promise到底是怎么回事儿,那因此呢,我们就通过使用,然后套倒推这个实现的方式来去手写一个promise,那如何去实现呢?我们先去打开我们的代码,把之前的呢先给它关掉,那么这里呢,我们通过这个新建一个文件的方式,一个note介的项目的方式来去实现这个promise,那这里呢,我们就先去创建一个蚂蚁promise这样的一个文件夹,那么在这个文件夹当中呢,我们打开集成终端,然后呢,去通过NPM以内的方式来去创建这样的一个项目,好,那么。
02:01
那创建好之后呢,我们这里新建一个文件叫做index.gs,那首先呢,我们来去看一看,正常的promise应该是怎么去使用的呢?我们知道前面我们用过阿贾克斯的封装时就用过了promise了,那现在呢,我们依然再一次的去使用一下呢,就是先去new一个promise new promise的时候呢,会传入一个函数,当然了,你使用箭头函数也是可以的,或者呢,你使用一个普通的function函数也是可以的,那这个函数呢,有两个行参,一个是成功的回联函数,一个是失败的回联函数,一般呢,我们就会起个名字叫做result,或者呢叫做reject OK,那成功或失败呢,都会去调用这个resolve或者是reject,那这里呢,我们给他写好,然后呢,为了方便呢,我们这里还是去设置一个成功,然后下面。
03:01
那也再去设置一个失败啊,就两个字创就可以了,来进行一个表示,这就是的最基本用法,那么此时我们会发现new promise时呢,你传入的这个对象它就会立即的去执行了,那因此呢,Promise本身它就有可能是一个类,那此时我们就可以去新建一个文件,比如呢,我们就起个名字叫做my promise.js,然后我们在这里呢,就实现我们自己的promise,那如何去实现呢?首先第一件事情就是promise是一个类啊,那么因此呢,我们就写一个class叫my promise。那我们也知道类当中呢,会传入一个函数,会立即执行,那么因此呢,就是一个。
04:01
Construct,那我们就需要接到这个函数,那它呢,就起个名字叫it q,然后我们接到这个函数之后,我们就可以调用这个函数,那调用时呢,它需要我们传入两个参数,这两个参数呢,分别是成功和失败的回调函数,那么这里呢,我们是没有这两个回调函数了,所以呢,我们就需要先去把这两个回调函数呢,先给它写好,那因此呢,我们就在类当中呢,先去定义这两个扩列函数,一个呢叫result,好,那同样我们使用这个箭头函数的方式来去给它实现,那还有呢,叫做reject也一样,我们使用这个箭头函数的方式来去实现,那此时我们在调用这个回调函数时呢,哎,我们就可以将。
05:01
当前的this.result以及this.reject给它传入进去,那这样的话呢,我们在使用时呢,它就可以调用promise给我们提供好的这个result和reject这两个函数了,这两个函数呢,你也能够看到,实际上就是在我们的promise当中呢,去定义好的,那调用时呢,就是传入进来去调用就可以了。注意再强调一下,我们现在是通过使用的这个方式来去反推promise应该如何去实现好,那么有了这些内容之后呢,我们也知道要调用这些方法,或者要调调用这个函数呢,它其实是有一个状态的更改的,这个所谓的状态更改是怎么个状态法呢?你默认情况下呢,它应该是一个喷顶,也就是等待的状态,那因此呢,我们就需要一进来就有这样的一个状态,所以我们这里呢,就先去这样做,给他来一个ST。
06:01
一个属性,那属性呢,我们就给他来一个叫做喷顶这样的一个状态,先去做标识,那这个喷淋状态呢,有可能在其他地方也会去使用,包括像成功的状态和失败的状态,那因此最好的方式呢,我们就可以定一个外面定一个全局的状态,那所以呢,我们就使用这个cost的方式来去使用这个喷顶,然后呢,我们就把这个喷底呢给它拿过来,所以这里呢,我们就直接使用这个常量喷顶来去替代好,然后紧接着我们还要把后面可能会用到的成功状态和失败状态呢,也给它先定义出来,那成功的话呢,就要fulfill,所以这里呢,我们就先给它定义好,OK,那的结果呢也就一样了,等于这个fulfill。
07:01
好,那么定义好之后,还有一个呢,是我们的失败状态也是一样,我们给它定义好,那这里呢,就是叫做rejected,那结果也是一样,我们就定一个叫做rejected OK,那么当前的这三个状态定义好之后呢,我们现在其实是只用到了一个,也就是定义了一个全局的等待这个状态,那么当我们去调用成功或者是失败的这个回调时,其实呢,我们就可以在这里先把状态给它做更改,这个状态的更改呢,其实就是更改了我们的this status,那直接让它等于这个fulfillit就可以了。那同样的道理呢,下面如果是失败的话,那我们就给它改成这个。
08:01
Reject,那这样的话呢,因为你的this.resolve和this.reject是当你去new的时候呢,就会去调用,所以一旦调用之后呢,哎,成功或失败呢,就会有状态的更改,但是呢,还有一个问题是我们的状态一旦更改了过后,比如呢,有默认的pending状态改为了fulfill,或者是改为了rejected,那我们知道promise的状态是不可逆的,那这种情况我们应该怎么去避免,它确实会在我们的代码中产生这种可变的情况呢?那要去做这样的一个阻止状态更改,就是需要在我们更改状态时先进行一次判断,这个判断呢也是非常简单的,我们直接去找到这个S,那如果它不等于喷点。
09:01
那么直接呢,让你返回一个啊,直接给你return就停掉了,也就是说你当前的状态不是喷你的情况下,我是不会做任何的修改的,那么反过来也就是说,如果你改变了状态了,那就不会去做其他的更改了,也就是说更改状态只有一种情况呢,就是当前处于叛逆的状态,所以呢,我们不管是成功还是失败,都要加上这样的一个判断,那么完成之后,哎,我们就可以使用点Z的这个语法来去调用了,那回到我们的this点那这个你带点介S当中,那我们就可以拿到这个promise对象,好,我们使用let的方式来去接受这个对象,Let promise,那么下面呢,我们就可以使用这个promise的拿到的对象,然后呢,去调用我们这个点Z这个方法了。
10:01
那此时呢,我们也知道啊,点Z这个方法呢,是接收两个参数的,一个参数呢,就是成功时的回量函数,另外一个参数呢,就是失败时的回量函数,也就是说呢,我们现在具体执行的呢,实际上就是通过这个reserve和reject的执行结果,所以现在呢,我们就可以去先调用一下传入这两个函数,那这是成功时的互联函数,那还有一个呢,就是失败时的互联函数,那我们呢,先把它写到这里,那到底是怎么去使用呢?此时我们调用这个Z方法,请注意是你new完promise中的一个Z方法,但是你回到你的promise当中,你会发现你的Z方法有吗?注意啊,你现在的promise里面呢,是没有方法的,只有两个被默认自动调用的这个resolve和reject方法,而一旦你完这个对象之后,里面就没有。
11:01
其他的方法可以去调用了,所以我们收起来就能够看到压根是没有拗成功之后可掉的这个方法了,那我们现在急需的就是new,成功之后得到对象的点Z这个方法,那意思呢,在蚂蚁promise这里呢,我们就可以去写一个then这个方法了,那和其他的呢也一样,你可以使用箭头函数的方式啊,也可以使用这种普通的函数方式,都是可以的。那么点Z方法呢,是接收两个参数的,一个是成功的回调,一个是失败的回调,所以这里呢,我们就需要两个参数来接这两个成功和失败的回调,Sus call back,那这个呢,就是我们的成功时的回调,那还有一个呢,就是失败时的回调,我们暂时先定义它为这个feel back OK,那么此时我们怎么去调用这两个回量函数呢?我们知道的。
12:01
是当成功时呢,会调用第一个,当失败时呢,会调用第二个,那我们怎么知道它是成功还是失败呢?哎,前面我们在调用时呢,哎,去更改过这个状态,而且这个状态呢,是当你去拗的时候呢,我就需要做更改的,那么因此呢,我这里就可以进行一个判断了,这个判断呢,实际就就是判断我们的this.status这个success的结果,如果是等于fulfill的,那么很显然我当前是处于成功这个状态的,那就开始去调用这个success call back这个函数就可以了,那I if,我们去进行一个判断,这个判断的结果呢,也是很简单,那就是C,如果等于等于rejected,那很显然。
13:01
那说明是失败的,那这里呢,我们就直接去调用这个f back就可以了,那这就是根据不同的状态去调用不同的回调函数。Z中传入的回调函数的方式呢,其实也是有参数的,什么意思?就是在我们的Z当中,如果成功之后,我们需要它给我返回结果,那就需要在回调函数里传入一个参数,比如叫it,那一般呢,我就可以在这里使用一个consoular log去把这个date呢打印出来,那失败呢也是一样,这里呢加一个ER,那就是error,那所以呢,我这里就使用consoular logo的方式,把这个error呢也给它打印出来,这就是成功,我就会把结果打印,那失败呢,我就会把错误信息也打印出来,那因此呢,我们传入的这个回调函数呢,实际上是有实参或者叫行参的,而在我们调用时呢,却没有,那这个结果怎么来呢?
14:01
如果成功了,那我在调用这个call back回调函数时呢,我需要把你异步的结果需要传入的,那这个结果我去哪个地方拿呢?那请注意,我们在执行一步时呢,实际上是在哪里执行的,实际上是在你new这个promise时就已经执行了呢?执行的结果会告诉你成功或者是失败,那么通过调用这个resolve的方式把成功的结果或者是失败的结果传入进去,也因此你的resolve和reject实际上就拿到了你的异步的结果,那么也就是说我们需要再一次的回到resolve和REJECT2个方法当中,那这里实际上就拿到了异步的结果,那比如这里呢,我们就使用这个value,而reject里呢,我们也使用这个OK。那么但问。
15:01
就在于我怎么把这两个结果能够传到我这个Z里面,供后面的点Z的结果去使用呢?那这个呢,其实也是非常简单的,我们拿到这个成功的结果或者是失败的结果之后呢,我们直接将这个结果挂载到当前的对象上就可以了,那当前的对象是怎么挂载的呢?也是非常简单,首先呢,我们就和定义一个全局状态是一样的,我们对当前的promise对象呢,定义一个成功执行呢,返回数据的一个默认属性,所这里呢,我们就使用这个value,等于案例发,先给它定义好那一样的写一个resign,等于一个案例范,然后如果这个结果是成功了有了,那我们就直接对当前刚刚写好的这个属性,也就是value直接把它重新复制,那失败呢也不例外,我们就直接使用Z0。
16:01
Re的这个结果,然后呢,给它复制就可以了,那这样的话,不管是成功和失败,我们都能够将它的结果存储到当前的这个对象当中,那既然当前这个对象在默认调用时就已经有了,或者叫处理了复制了这个结果,那我们再一次的去调用使用这个对象,也就是前面promise对象去调用点认时呢,哎,这个结果实际上也是有的,那么也就是说我们在调用这个success call back的时候呢,我们就可以把this.value给它传进去,那如果是失败的话呢,同样的道理,我们就可以把this点这三给它传进去,好,那这样的情况呢,我们就能够把这个promise处理成功和失败的这个结果呢,那就全部都拿到了,那点赞呢,也就封装结束了,那最后我们怎么去使用呢?我们在最后的时候呢。
17:01
通过model OK,通过model第2XP的方式来去对这个对象呢,导出在这里呢,就是MY蚁promise,那导入之后呢,我们就可以在index这里呢去导入了,导入和导出呢,其实也是非常方便的啊,这和我们的普通的note JS没有什么太大的差别,那这里呢,我们就使用这个cost,然后呢把这个my promise导入IQI,好,我们导入呢就是当前的my promise,那么这里呢,我们依然是new的javascript里面给我们。
18:01
提供的promise,那接着来我们把它换成我们自己封装过的这个蚂蚁promise的方式,好,那现在我们就来看一下,当我们去new这个promise时,发送的成功和失败能不能够在promise.z的方法里面去打印出来,那现在呢,因为成功和失败只有一个,所以说呢,我们就先去使用这个成功,那接着我们这里呢,去使用noe的方式去进入到我们的这个啊,先使用CD的方式进入到我们的这个my promise里面啊当前呢,我已经进来了,好,我使用PW看一下,OK,然后接呢,我使用这个node来去调用这个index.js,那么现在我们就能够看到,诶这个成功的就已经成功的打印出来了,好,我们再往上拉一拉,OK,那如果我要去调用失败的话呢,其实也是一样的,我们看看能不能看到这个失败的结果,好,这个呢也是没有问题的。
19:01
那这就是对于我们promise的一个基本的逻辑的封装,它的基本逻辑呢,也是非常简单,就是通过new promise的方式和使用promise.z的这个方式来去倒推,我们应该怎么去封装这些内容,那么这些写完之后呢,还有一个最大的问题就是如果我们在使用new promise时呢,真的去使用了一个异步的方式,比如这里呢,我们使用这个set time out,因为刚刚呢,我们并没有去做异步的任何的操作,那现在我们真的去加一个异步,比如这里呢,我们就写一个2000,就是两秒钟之后呢再执行,那执行成功之后,我这里呢,再去调用我们这个成功的回调,那失败的回调呢,我们先暂时把它给取消掉,那接着呢,我们来看一看能不能去处理我们的伊布,此时你会发现我这里呢,好像卡了一下。
20:01
卡了多长时间呢?其实就卡了两秒钟,但是呢,并没有把我的这个成功给打印出来,那它的原因是什么呢?请注意,我们在promise里呢,只判断了两个状态,你再去调用点时呢,我们只是判断了你当前是成功还是失败的状态,那当你去使用new promise时,来去执行set的这个过程中,你其实已经拿到了这个对象,并且调用了点Z,而在调用点Z时,你传入的这个函数呢,也会被立即的去执行,那么一旦执行呢,它就会去判断这个结果,那当前是一个什么样的状态呢?哎,请注意,因为你前面并没有去调用这个resolve啊,为什么呢?因为等两秒钟之后,这个resolve才会去调用,而失败呢,也没有被调用,那因此呢,你当前的这个状态呢,就一定是处于这个喷NY的状态的,那么也就是。
21:01
是意味着当我们的Z去判断当前状态时呢,成功的状态是不成立的,而失败的状态呢也是不成立的,所以你调的点Z呢,没有一种状态是能够符合当前的这个状态的,那因此你在命令行中呢,其实就看不到任何的结果,那这应该怎么去解决呢?
我来说两句