00:00
好,这节课我们来讲依赖收集,依赖收集呢,可以说是咱们呃,整个这个数据的这个响应式的范畴当中比较复杂的一个知识了啊,但是比较诡异的是呢,就是很多的书和博客都是先去讲依赖收集,然后再去讲什么数组的真听啊啊,然后这些东西啊,还有observer,实际上呢,这个顺序呢,呃,老师觉得是有点问题的啊。那是那么咱们这个课啊,就是之前已经把这个observer类,还有observe函数已经写稳了数组啊,还有对象的这个呃递degree啊,就都已经整明白了,然后咱们来看依赖收集啊,依赖收集呢,确实有点麻烦啊,它主要麻烦就麻烦在呢,它这个东西呢,你得需要有一个想象力啊,它这个东西到底是怎么回事啊,那咱们慢慢说。首先呢,什么是依赖啊,什么是依赖,依赖这两个字呢,其实跟咱们NPM那个依赖是没有关系的,我们在这里的这个依赖呢,指的是咱们用到数据的地方。
01:10
啊,就你什么地方用到了数据什么地方呢,就叫做依赖。好,那么在V1当中呢,它的依赖呢,是细力度的啊,就用到数据的倒墓是依赖。啊,也就是说有一条DOM用到了我们的数据双大括号A了,好,那这个呢,就是呃,依赖。但是我们VV2呢,改改变了,它叫做中等力度的依赖,就是用到数据的组件变成依赖了。那也就相当于我们现在这个A呢,它对于哪个组件来说是影响它视图变化了,对吧?哎,那么他说,那你说老师一个A它怎么会影响多个视图呢?当然可能了,比如说有pros对吧?诶去传入到子组件当中,它可能会影响这个组件。那这个时候你就会发现组件由于是这个数据的依赖,那么也就是说当这个数据发生变化的时候,我只要通知到组件就可以了,那组件它里面是不是就有地F算法和虚拟函数虚拟do呀,咱们在之前的课程当中已经讲过了。
02:16
所以组件呢,它这个时候就会开始进行diff了,Diff的话就会把视图给进行改变掉。那么还有一句话呢,叫做在get中收集依赖,在C中触发依赖,这句话呢是非常非常有哲学的啊,这也是游禹锡的一个创新的点,创新之处。什么呢?就是说我们这个依赖呢,要被收集起来啊,然后呢,以备在数据变化的时候,要通过循环的形式来通知所有的依赖。那我怎么收集这依赖呢?诶,那用到的地方它不就会触发get吗?那谁触发get了,谁不就是我的依赖吗?对吧,所以它这个就特别的巧妙啊,就是在get中收集依赖,在C中呢,我们触发依赖。
03:03
所以在这样的一种情况下呢,我们来看一下这个图。啊,这个图呢,实际上就讲了DP类和water类,这是最难的两个类啊,这两个类的代码其实不难,但是呢,很多同学不知道它是干嘛的。我们来看,首先第1P呢,一看这个单词你就知道了,是英语dependency啊,就是依赖这个单词的首字母,所以呢,他就负责是把依赖收集的代码呢,封装到它里面,他专门用来管理依赖,也就是说每个OB observer的实例呢,它的成员中都有一个DP的实例。啊,这个大家一定要注意,就是DP在哪实例化,在observer的实例中。Observer是什么?咱们回想一下咱们之前的这个程序啊,可能大家就已经懵了,咱们打开咱们刚才写的这个observer observer在什么时候被实例化呀,对,Observer当中也就相当于每一个啊这个。
04:02
呃,就observer,然后然后然后然后这个observer里头,他不会又会去那个observe这么一项吗?或者说是DeFine activity,然后activity当中不就会有它吗?对吧,它是一个循环递归的一个过程,所以说这个每一个observer的实例,就只要我拗了observer的实例,那么它里面一定就会有一个第一批的实例。啊,一定就会有一个DP的实力啊,是这样子的,那么water呢,是一个中介,数据发生变化的时候呢,会通过water中转来通知组件。所以这个图呢,大家可以发现在这个图当中,你就会发现他这个就很好啊,这是VE的一个官方的图片。什么官方的图片呢?就是render,这里有个touch touch是什么意思?表示触摸,什么叫触摸呢?就是我。模板引擎啊,对吧?诶模板引擎当中肯定会有,比如说说那块A,那这个时候是不是就表示我用到了A啊,那这个时候就表示touch啊用到了A,那用到了A的时候,这个时候它这个时候我我们既然用到了这个A的话,那这个时候的话,它就在get中就会收集依赖啊,这个get中呢,咱们现在就会收集依赖,好收集依赖的话是需要使用咱们第1P这个类的一个底depend的啊depend的这个方法,哎,Depend的就表示依靠啊,就把它给收集了。
05:18
好了,那么在center中呢,干嘛呀?对,你看刚才说了是不是触发依赖,所以在这时候触发依赖,触发依赖的话就是notify啊,调用notify这个方法就能触发依赖,那么你会发现,不管是收集依赖还是触发依赖呢,实际上收集收集的是water,触发呢,触发的也是water。啊,这个呢,就会让人觉得很,嗯,很疑惑,说这个water到底是什么,这个water是个很抽象的东西,咱们一会去写代码你们就知道了,然后water呢,去触发视图的一个重新的更新,是这样子的啊然后这个组件呢,就用这个虚拟节点和地步算法来进行页面的一个更新,它是这样子的一个。啊,一个东西。所以言呃言外之意是什么呢?言外之意就代表咱们再来看一张图啊,再来看一张图,就这张图啊,这张图的话,它这个是图片来自CSDN的啊,那么这张图的话,咱们是由于是别人的劳动成果是吧,所以老师咱们也不敢说这个,呃把这个图片直接拿来用,咱们还是把这个原地址贴一下啊好,那么这张图的话其实也很清楚,哎,那这张图的话,实际上就告诉你了observer的一个关系啊,因为这里没有observer,发现了吗?所以这张图呢,就把这个observer就弄出来,就是data要被observer变成呃响应式的。
06:35
然后这个observer呢,就会是叫什么DeFine react啊,然后在这里头呢,就有gitter gitator呢就会去收集啊,啊这个收集来,然后到这个water,收集的是water,然后塞呢就会去通知对吧?哎,那收集依赖收集到哪呢?第一批里啊,第一批的那个依赖就是water。啊,然后第一批的通知这个waterer对吧,那你说老师这个图到底是干嘛,所以说他就比较比较麻烦,就把waterer和第一批加进来之后就比较麻烦,慢慢学,别着急啊,然后咱们现在为了加深大家理解呢,咱们再看几句话啊,首先呢是依赖,就是water,只有water触发了get才会收集依赖,哪个water触发了getter啊,这写错了叫触发了get。
07:15
哎,就把哪个water收集到第一批中,第二个呢,是第一批使用了发布订阅模式,当数据发生变化的时候呢,会循环依赖列表,把所有的waterer呢都通知一遍。代码的实现的巧妙之处就在于waterer把自己设置到全局的一个指定位置啊,然后读取数据,因为读取了数据呢,所以它会触发这个数据的get,然后在get中呢,就能得到当前正在读取数据的water,并把这个water收集到DP中。啊,同学们很有可能现在已经懵了,这块确实很难很难理解啊,那没关系,咱们现在的就慢慢通过代码咱们来去进行一个讲解啊。好,首先呢,我们先去创建啊两个新的类啊,那这两个类呢,第一个叫做第1p.JS,我们就向外暴露啊,Export default class对吧?哎,那这个类我们把类名写上叫第一批。
08:12
啊,我们向外我们就直接就是暴露啊,默认暴露一个第一批这个类,好,然后再去创建一个文件,这个文件的名字呢,就叫做water.js啊,然后它呢,向外暴露这个waterer wh对吧?哎,Water DEP和这个waterer,然后我们现在呢,把这个constructor都加上啊。好,然后这个第一批,那这个时候我们就可以去实例化,就是我是第一批啊类的构造器。好,然后在这里呢,我们也去写,就我是water类的构造器啊,好,那么把这两个类弄完之后呢,我们先去实例化它啊,为什么呢,就是说老师啊一直在琢磨,就是怎么样才能给大家把这个事儿呢讲的更明白一点。
09:02
啊,那实际上呢,就是咱们先去实例化它。啊,先去实例化的啊呃,我先把这样直接写成一个z.a加加吧,啊改成一个简单的啊一种形式A不是z.a是塔。揉鼻勾啊。好哎,OB勾,然后A加加,然后这会因为没有负值啊,所以说如果负值的话,它这就有这个值了啊好,那么现在的话呢,我们先去实例化,它实例化呢,我们先去实例化谁呢?我们先去实例化第一批。DP要在哪里实例化呢?它要在observer中去实例化啊,那么这句话呢,其实在刚才笔记上就有了,这儿呢,就说的是每个OB observer的实例呢,成员都有一个第1P的实例,这句话一定要记住啊,这句话一定要记住,因为这几个类呢,是比较关系比较微妙,比较错综复杂的啊,然后如果说你真的呃,朦朦胧胧的懂,就是特别呃这个什么的话,那其实说实话他能把你绕晕,但是呢,咱们不能把你给绕晕啊。
10:06
所以这个时候呢,我们就知道了是在哪。对,就是在这儿啊,在observer这,我们要去新增就是自己的第一批,好等于new一个第一批,看见没有,我们先把拗给你写出来啊,让你开心一下。啊,先把new给你写出来。所以在这里呢,就相当于就是说每一个observer的实力对吧,身上啊,都有一个第一批第1P的这样的一个啊一个实力,那就是他要收集这个依赖,那欧observer是什么?咱们先去引包,诶这引包帮你引了,自动引了。那么observer是什么?Observer的话,咱们刚才说过,Observer就是他自己嘛,那observer是什么?对,他的初心是什么?是不是就是将正常的object转换为层级都是响应式的这么一个东西,对吧?那什么时候会调用object observer是不是任何一个层级都会调用对吧?因为我这个地方是DeFine啊在这呃,Work了,Work不是DeFineive了吗?DeFine reactive的话,他在那又会去进行一个叫observe的一个操作,Observe的话又会调用observe嘛,那所以说这样的话,每一层是不是都会有一个DEP。
11:19
你想一想对吧,每一层都会有一个第一批,这这个这个大家应该能听懂,就是你这个数据层次有很很多层啊,那么就比如说咱们现在这个index。那也就是说对于这个对象来说,它只要是对象,它就要有一个啊第一批,比如说这外层这个是一个对吧,一个啊,然后这A是一个两个,这M是一个,这N就不算了,因为这N是个常数对吧?哎,所以说就是呃,一个两个三个啊,然后这个不算,这是四个,然后这是五个,这是六个,然后这是七个啊,所以应该一共七个,第一批咱们来刷新看一下啊,刷新你看一个两个,三个,四个,五个,六个,七个正好是七个啊,这为什么是七个,你一定要能数出来。
12:00
啊,一定要能数出来,为什么是七个第1P,因为observer被执行了七次啊,为什么被执行了七次?对,因为是,哎,没错,所有对象啊,就这个普通值,不算普通值的话,不是已经在这个OB observe这已经被返回了吗?对吧,哎,数组也算是啊,数组也是object呀,对吧,所以这个时候是其次再数一遍,最大的一个A2个M第三个啊,然后C第四个啊,D是第五个,E是第六个,然后这是第七个,所以这是第七个啊,那第一批被执行了七次啊,这个咱们要明白好。然后呢,这个时候呢,我们就要明白,就是这个water是干嘛的啊,Water是调用watch函数产生的。啊,然后呢,它会保存什么,它会保存咱们每一次你要watch这个东西的一个回调函数。啊,回调函数,然后在数组当中呢,啊,我们嗯,需要保存有这个water的所有的第一批啊,是这样子的啊,但是但是这个东西来说的有点这个玄乎啊,所以说我们慢慢来,那现在的话,我们要打开这个DeFine react。
13:08
啊,然后在这里呢,我们也要引入第一批。哎,也就是第一批这个这个东西呢,有两个文件在引,看见了吗?有两个文件在引。啊,那也就是说我每次我进行一个这个function啊,这个呃,DeFine reactive的时候看见了吧,哎,这块的时候啊,那我在这的时候,我就需要在这里去,呃,去这个什么啊,去得到他自己这样把这个第1P,我们现在给他拗出来,在这里要拗一下。哎,扭一下没问题,那这样的话呢,它就什么意思呢,这样的话你就回到这index你就明白了,就是说。就是说我这个OB勾,它不是里头有个杠杠OB,然后杠杠第一批嘛,对吧,就这个O它的第一批,那它实际上这个第一批呢。它就保存的是咱们这个OB勾的DP。
14:01
对吧,然后咱们这个A呢,它是B包中,它是有这个OB勾的这个A当中的这个第1P,就B包当中有OB勾的A的第1P,对吧?然后OB勾的那个杠杠啊杠杠OB的那个杠杠的第1P呢,它实际上是保存的是OB勾的A的这个第1P。对吧?哎,当它每一层都有,那这个时候其实可以输出这个OB勾啊,输出这个OB勾呢,咱们来看一下它是怎么回事。你看这不是A属性吗?A属性是10B是A啊它这个这这这这个这个这个这这这个这就有点奇怪了啊都都啊对,因为A属性变成十了,我说呢啊,我说这怎么回事呢?你看这A属性,这不OB勾吗?那OB勾里头是不是有个杠口OB对吧?然后杠口OB,你看这里头是不是就有一个DEP这个东西发现了吗?然后M打开之后呢,这个N。N啊,这里头都会有这个第一批,都会有这第一批的东西啊,就只要是对象。对吧,B是常数没有,C是一个对象,打开之后你看这是不是就会有一个OB里头是不是有个DP。
15:04
啊,那现在你可能不知道这第一批是干嘛的,你先别管,就是第一批是干什么的,这件事呢,其实呃,一会你就知道了,但是现在你先知道他他第一批出现在哪里。DP是不是出现在每一个对象这个层次,然后它展开之后呢,杠杠OB里面啊,这个东西是个observer类型的一个对象,然后他有一个DP属性。对吧,它的这个第一批属性呢,哎,里头有这个啊就行了,咱们只要能明白啊就OK了。对吧,哎,OK了啊,就只要你呃能慢慢的把这个读懂,对吧,哎,就OK就行。好,然后接下来呢,我们这个时候就看这个DeFine reactive DeFine reactive当中呢,这个地方啊,我们就要来看,就是我们不是说嘛,这个get要去干嘛,是不是收集依赖,然后set是不是要去通知依赖,对吧,那这个时候呢,我们就可以,因为这有个第一批嘛,对吧,我们就可以在这set当中,我们这个时候就是啊嗯,叫发布订阅模式啊,叫发布订阅模式啊,我们就要去通知啊,通知咱们这个第一批。
16:12
啊去进行一个改变,那所以说咱们就第一批就notify啊,那这个时候肯定会报错,因为你没有定义notify函数啊,它就会报错啊,当然为什么这样不报错,因为你没有set呀,对吧,我index这我得set一下呀,比如说我现在让这个OB勾。对吧,哎,OB勾的A,嗯的M的N,呃,等于一个八八对吧?哎,那这个时候你看它就报错了啊,因为你这notified是没有定义的。啊,所以说我这里是不是要去有一个notify,哎,这里要有个notify,那为什么要有notify,其实就是刚才咱们PPT上这张图啊,这张图大家可以看一下,就是我的data当中C是不是要去有一个notify在这。对吧,哎,那你说老师你怎么编程的这个顺序怪怪的啊,咱们是这样,就是老师呢,其实是讲过很呃好好多年就是vuee的这个底层啊,那么实际上这个时候呢,最适合初学者的啊,就是现在老师给你们讲的这个顺序。
17:16
啊,就是你你们先不要去写第1P里的那个啊,很多同学看书看博客,知道这里头有一个这个数组。啊,然后在这里要循环数组发布啊,没必要你先给他实例化出来啊,就是你先乖乖的听话,你先把它实例画出来,在这里有一个实例化。对吧?哎,然后在刚才这个observer这也有实例化啊,Observer这个实例化的目的是让他绑到刚刚OB上,那这DeFine reactive这个是不是让他B包中啊,对吧?这个第1P是不是就是B包中的那个,就这个是不是就是这个Val这个B包,因为Val是什么OB不就可以看作是这一层,就是这个对象这层get和side那个B包当中的这个DP吗?对吧,那这俩第一批不是一样的。
18:00
啊,这个你给慢慢悟,对我在这这样我调用这个notify了,这notify的话呢,那我这边的话我就可以CAno.log啊,咱们现在来看一下这块,就是我是no t five。好,然后刷新就能看见我是notify啊,在这儿就会执行一次,它只会执行一次,因为你这个数据就改变了一次嘛。哎,我是note版对吧,哎,到这就OK了啊,就就是到这就OK了,然后数组的话呢,其实也是需要被改的。啊,数组也是被要被改的,就是相当于什么呢?相当于你这个数组不是OB已经拿到了吗?我看看这个数组啊在这啊,这个数组不是拿到OB了吗?对吧,所以说你这个东西就相当于要在数组上是不是也得通过呃第一批,然后再来notify。对吧?哎,Notty版这个也得note版,那这样的话,假如说你数组被更改,比如说你的OB勾点G,我们push一个六六,那这个时候呢,它也会触发这个not板啊,我们现在刷新,你看他也会触发not板啊,所以说你这个数组这个不能忘了写,如果把它注掉了,那你这块是不是就没有我是OT板。
19:07
对吧?哎,所以说一定要记住就是数组这一块呢啊,他也要有一个我是notty啊,我先把这数组住了啊行,咱们这节课呢,咱们就先讲这么多啊,咱们就先讲这么多,那你说老师你还是没有写第一批的核心代码,也没有写watcher的核心代码,对啊,这就是老师这多年的讲课的经验的一个顺序啊,你们就按照老师的这个方法啊,先去定义这两个类啊,然后硬着头皮实例化的啊,硬着头皮实例化的记住在哪实力化啊,两个地方,一个是方react的币包当中,还有一个就是observer的这个身上。啊,为什么要这么做,自己去考虑一下啊,哎,然后你就其实就就能想明白对吧,一个是绑在他身上的,还有一个是我为了创建让他有响应式的时候,B包当中能得到那个DP。对吧。哎,好,然后咱们下个视频去书写他们这里面的源代码啊。
我来说两句