vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期

        在vue2.0中,我们经常会看到下面这张生命周期图,本次结合源码来让大家对这张生命周期图有一个简要的了解。

3df511c588744d36e6a22d886eb18153.png

1.beforeCreate和created:

        src/core/instance文件夹为vue方法初始化的主文件夹,入口为index.js文件。在使用vue框架的时候,我们首先要通过new Vue初始化一个vue实例:

9496789cf717e1479312c46dcd235a7a.png

        此时是通过Vue方法中的_init来完成初始化的,我们再来详细看下_init方法:

d5a3968ac7106e4abe49afd566d9318a.png

        在_init方法中通过initState来初始化实例中要用到的data和props,在初始化相应式数据的前后,分别来调用beforeCreate和created钩子,所以在beforeCreate中是不能访问实例的data和props数据的,而created可以。

2.beforeMount和mounted:

        为了能够更加全面的了解vue挂载的整个过程,来看runtime-with-compiler的代码。在使用vue-cli脚手架来安装项目的时候,经常会遇到runtime或者runtime-with-compiler的选择,这两个是什么意思呢?其实在vue中,把模板template转化成render函数的过程就叫做compile编译,一般在使用webpack打包的时候,我们会通过vue-loader插件在打包的时候就把模板转化成render函数,这样用户访问时就可以直接渲染出vnode挂载到浏览器页面,来提高挂载效率。如果我们没有通过webpack预先进行打包,而且我们在vue组件中写的是template模板的话,就需要通过runtime-with-compiler的模式,在运行时进行编译。

        在platforms文件夹中,有两个子文件夹分别是web和weex,他们的作用就是能够让vue的核心源码所产生的vnode节点树能够适配多个平台的DOM方法,从而在多个平台上运行。我们主要看web平台:

080c9e500a0adaf73ffe7d606dd13a18.png

        这里作者非常巧妙地将vue核心的mount方法与web平台mount时所需要的编译逻辑相结合,作者先是把vue核心mount方法缓存起来,再给实例的mount方法重新赋值,最后再调用vue的核心mount方法,进行挂载。在平台的mount函数中是通过compileToFunctions方法得到render方法,以便后续mount时生成vnode节点树。

        在web平台的mount函数中进行compile,生成render函数之后,就进入了vue通用mount函数流程,mount函数主要是运用mountComponent函数来执行挂载:

1c8ea11239e8d4334a764b8b9975e2fd.png

        mountComponent函数在lifecycle.js文件中,首先执行beforeMount钩子函数。接着为updateComponent函数赋值:

updateComponent = () => {
    vm._update(vm._render(), hydrating)
}

        传给Watcher构造函数,此处初始化Watcher的作用就是作为管理当前正在渲染的实例的渲染,所以叫做render watcher。Watcher的构造函数如下,下面我们先来看看Watcher在实例化的时候都做了什么(提示:可以先看图后的解析):

a0864e2536379b62dd9afc6c4ef46a9b.png

  Watcher类在src/core/observer/watcher.js中,实例化的时候会执行到this.get(),在get函数中会执行pushTarget()将当前Watcher赋值为当前的渲染watcher。(Watcher是一个监听者的实现)this.getter.call()即执行刚才所赋值的updateComponent函数。进行_render()和_update(),可以结合下面的流程图来理解实例的渲染流程,执行render函数后,生成了vnode节点树。执行了patch函数后,又生成了DOM结构,挂载到浏览器上后,再执行mounted钩子。

f990f55712088953dd0c318e6323b680.png

3.beforeUpdate和updated

      下面来分析beforeUpdate和updated钩子,不过我们需要先来理解一下vue的响应式实现。在init的过程中有通过initState初始化data和props数据。本次主要讲data的初始化,在data的初始化的过程中vue只做了两件事,一个是对定义data函数返回对象的遍历,把vm._data.xxx都代理到vm.xxx上;另一个是调用observe方法观测整个data的变化,把data变成响应式。

0d622590be12269f60984d9b8398c888.png

   Observe是在src/core/observer/index.js文件中,为每个响应式对象value创建一个Observer实例。

86609619620d168c5e140b77b95f2c33.png

        Observer函数将在传入的value对象中添加一个”__ob__”属性,将自己赋给这个属性。如果value是数组调用observeArray函数,来对每个元素单独执行observe。不然对value执行walk,在walk中执行defineReactive函数。

7f855648aea22a772f5666f338c0feb5.png

        只有在defineReactive中,才对继续对元素真正实现响应式,即通过Object.defineProperty给对象的元素赋get和set属性。注意vue没有对数组的每个元素调用Object.defineProperty。只在数组对象上调用了Observer()。

0600810376e7b562145d0575cb495f36.png

        至此讲完了vue如何实现响应式。

       上小节讲到在渲染的时候会将当前Watcher赋值为当前的渲染watcher保存到全局,再执行render函数生成vnode节点树。在生成vnode节点树时,会访问响应式对象的值,就会调用响应式对象的getter属性。所以,在初始化中实现对象的响应式之后,getter属性函数执行依赖收集。

        还是看上面的get函数,首先检查全局的渲染watcher是否存在,如果存在调用闭包中保存的dep的depend()。与watcher相对应,dep作为被监听的对象,被保存在data的数据对象当中。如下图,当dep调用depend()时:

35a016811842a0cb5a5366131d813f0f.png

        全局渲染watcher会调用addDep()把当前的dep保存到watcher自己的依赖数组中。代码如下,然后再调用dep的addSub方法,dep依赖将当前的渲染watcher保存到自己的subs数组中,留待在调用set属性函数时调用notify函数(如上图),来通知subs数组里保存的watcher:

688ceb54d7f8cde7fce0e5329ac044f7.png

        整体的逻辑关系总结如下:getter()产生了响应式数据中dep的depend调用,之后这个dep与当前的渲染watcher分别调用addSub和addDep方法,分别记录了彼此。在setter()时,dep调用notify,来逐个调用监听它的watcher的update方法。

22ddaa25938ae79b9800520ac97e6a02.png

    了解了整个响应式流程,我们来关注下vue在哪里调用beforeUpdate和updated钩子。上文提到响应式数据会让watcher调用update,函数如下,在update函数中会调用queueWatcher:

a1a407c02f855f3eac16f414c39b69d9.png

   而queueWatcher会调用flushSchedulerQueue方法,代码如下:

5680d56a338e397c7cfe0e2be3405099.png

      在flushSchedulerQueue方法中会调用watcher的before方法,即初始化watcher时传入的beforeUpdate钩子,最后调用callUpdatedHooks来调用updated钩子。

cf20df12df633c0af9e9b3ba9b8d7600.png

6e56b65d7f090e8789e8b4fa5917481e.png

4.beforeDestory和destroyed

      最后来分析beforeDestory和destroyed钩子,其实这两个钩子是比较简单的vue通过一个原型方法调用了这两个钩子:

1d369f3f9591d772961f484d8570c19a.png

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值