vue数据入口initSate开始分析数据驱动更新原理

裂谷
• 阅读 1695

前言

读这篇文章前,最好是先读vue数据绑定源码,因为本篇是接这章写的,放在一篇文章里,篇幅太大,我只好分成两章了。

初始化vue实例

Vue.prototype._init = function (options) {
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm) // 初始化数据的入口
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')
    
    if (vm.$options.el) {
      vm.$mount(vm.$options.el) // 挂载组件
    }
}

// mountComponent是在挂载组件时调用的方法
export function mountComponent (vm, el ,hydrating) {
  callHook(vm, 'beforeMount')

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

  new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */)
  
  if (vm.$vnode == null) {
    vm._isMounted = true
    callHook(vm, 'mounted')
  }
  
  return vm
}

initState

上一篇文章,我们已经了解了ObserverDepWatcher都是负责什么?如何互相协作?
接下来,我们从数据的入口开始,了解vue是如何使用这几个类完成的数据驱动视图更新的?
初始化state,就是初始化这几个属性。

vue数据入口initSate开始分析数据驱动更新原理

先讲下什么是可观察者对象呢?
具备两个条件:
1、取值的时候,能把要取值的watcher(观察者对象)加入它的dep(依赖,也可叫观察者管理器)管理的subs列表里(即观察者列表);
2、设置值的时候,有了变化,所有依赖于它的对象(即它的dep里收集到的观察者watcher)都得到通知。
watcher里面存储它都观察了谁(dep),dep里面存储了都谁观察了自己。

initProps

vue数据入口initSate开始分析数据驱动更新原理

循环每个props属性,对每个属性调用defineReactive,把每个属性加上getset装饰器,变为可观察者对象,如果属性值是对象也会递归转化。

initData

vue数据入口initSate开始分析数据驱动更新原理

observe就是循环把data中的所有项都转换成可观察者对象,如果子项是对象或数组就递归转化,确保data里的每一项及其后代都转化成了可观察者对象
初始化数据时,不管data里的数据渲染用没用到,都会转成可观察者对象。
对于propsdata,只有哪个watcher用到了去读取时,才会把该watcher加到他的观察者列表中。

dataprops里都调用了proxy这个方法,他是做什么的呢?
proxy(vm,’_data’,key)
proxy就是把dataprops下的属性都代理到了vm实例下,vm._data.a等价于vm.a
原理就是Object.definePropertyvmkey属性设置getset方法,当访问get的时候,返回的是vm._data[key];当访问set的时候,设置的是vm._data[key]的值。

initComputed

vue数据入口initSate开始分析数据驱动更新原理

初始化计算属性,就是为每一个计算属性定义一个Watcher观察者对象。这个对象是lazy的,不会立即就去执行计算(即get方法),等到用的时候才会去计算,这个时候就会去读取这个计算属性依赖的可观察属性的值来计算,读取的时候就会把这些依赖添加进这个计算watcher里,同时这些依赖的订阅者列表也会加入这个计算watcher。所以当依赖变化时,通知到他的所有订阅watcher。计算watcher接到依赖发生变化了,不会立即计算新值,而是标记dirtytrue,读取这个计算属性的时候,发现dirtytrue,就是说数据已经不是最新的了,需要重新计算,然后才去计算,否则直接取上一次计算的值value

如果某个data通过计算属性间接的被用到了渲染里,那么这个data也会被加入到渲染watcher的依赖列表,它的订阅者列表也会保存渲染watcher
只有当模版里使用了该计算属性,这个计算属性依赖的可观察者才会被加入到渲染watcher的依赖列表。如果模版里没有直接或间接用到可观察者对象属性,那么当你set它的时候,也就不会触发更新操作。

initWatch

vue数据入口initSate开始分析数据驱动更新原理

初始化watch,就是为每个watch属性创建一个观察者对象,这个expOrFn解析取值表达式去取值,然后就会调用相关data/prop属性的get方法,get方法又会在他的观察者列表里加上该watcher,一旦这些依赖属性值变化就会通知该watcher执行update方法。即会执行他的回调方法cb,也就是watch属性的handler方法。

到这里,数据的初始化就完成了。

mountComponent

vue数据入口initSate开始分析数据驱动更新原理

这个方法是在,所有的数据初始化完成后,执行挂载组件时调用,创建一个渲染watcher,每个组件有且仅有一个渲染watcherupdateComponentwatchergetter属性,创建后,立即调用get方法,即是调用updateComponent,也就是调用render方法,render里使用了的数据就会读取相关的dataget方法,就会把data的依赖加进这个渲染watcher的依赖列表里,datasubs也会加入渲染watcher,如此,当设置data时拦截的set方法就会通知渲染watcher调用update方法。

我总结下:
一个数据变更后,通知他的Watcher去执行update。
不同类型的Watcher职责不同,vue里的Watcher可以分为3类:
渲染Watcher、计算Watcher、侦听器Watcher,注意这3中Watcher的getter属性分别是什么。

  • 渲染Watcher的update,负责重新渲染,执行render;getter是updateComponent。
  • 计算Watcher的update,负责标记dirty,告诉它数据不是最新的需要重新计算了;getter是计算属性的get方法。
  • 侦听器Watcher的update,负责执行回调方法,也就是watch的handler;getter是watch的取值表达式。
点赞
收藏
评论区
推荐文章
02-Vue入门之数据绑定
02Vue入门之数据绑定02Vue入门之数据绑定2.1.什么是双向绑定?Vue框架很核心的功能就是双向的数据绑定。双向是指:HTML标签数据绑定到Vue对象,另外反方向数
Easter79 Easter79
3年前
vue 生命周期的理解(created && mouted的区别)
生命周期先上图(笑skr个人~~)!(https://oscimg.oschina.net/oscnet/6d899c3576884ee9db73c0263ac9f4027e0.png)什么是生命周期Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程,我
Easter79 Easter79
3年前
vue(原理)_数据绑定
一、前言1、数据绑定原理2、在数据绑定中四个重要的对象3、具体实现3.1初始化阶段3.2建立Dep和watcher的联系阶段3.3更新阶段二、主要内容1、数据绑定原理(1)概念:一旦更新了某个数
海军 海军
4年前
2021前端技术面试必备Vue:(二)组件篇
上一章已经更新了Vue基础,那么本章将更新Vue中最重要的概念组件,会介绍到组件的使用,组件传值,插槽的使用,插槽的分类。当第一章基础掌握差不多了,然后再学习了组件的开发,那么你就可以开发简单的Vue项目,路由文章还没有更新,学习完Router后,就可以开发实战项目了。<sectionid"nice"datatool"mdnice编
CuterCorley CuterCorley
4年前
uni-app入门教程(8)在uni-app中使用Vue
前言本文主要的主要内容是在uniapp中Vue的用法,具体如下:Vue支持响应式数据操作,可以实现数据和事件的绑定,同时支持this传递;uniapp在Vue实例生命周期的基础上增加了应用生命周期和页面生命周期;实现全局变量的3种方式,即公用模块、挂载Vue.prototype和globalData;Class和Style的动态绑定,包括对象
Tankard825 Tankard825
4年前
Vue入门系列之Vue实例详解与生命周期
Vue的实例是Vue框架的入口,其实也就是前端的ViewModel,它包含了页面中的业务逻辑处理、数据模型等,当然它也有自己的一系列的生命周期的事件钩子,辅助我们进行对整个Vue实例生成、编译、挂着、销毁等过程进行js控制。5.1.Vue实例初始
Python进阶者 Python进阶者
4年前
Vue的学习笔记(中篇)
一、什么是Vue.js?Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue也完全能够为复杂的单页应用提供驱动。上篇文章我们讲述了基础,可以戳这里:。这篇文章我
海军 海军
4年前
2021前端技术面试必备Vue:(四)Vuex状态管理
前三章陆续已经更新了Vue基本使用和VueRouter的基本使用,如果你读了前三篇文章的话,并且掌握差不多,那么你现在可以开发简单的应用了,例如Blog,电商网站........唯一不足的是,随着你的业务需求不断增加,页面中的状态数据也不断庞大,维护起来就特别困难了,Vue提供了一种状态管理解决办法Vuex,它的思想和React的R
Stella981 Stella981
3年前
34条我能告诉你的Vue之实操篇
这是我学习整理的关于Vue.js系列文章的第一篇,另外还有两篇分别是关于优化和原理的。希望读完这3篇文章,你能对Vue有个更深入的认识。7种组件通信方式随你选组件通信是Vue的核心知识,掌握这几个知识点,面试开发一点问题都没有。props/@on$emit用于实现父子组件间通信。通过
手牵手带你实现mini-vue | 京东云技术团队
Vue的双向数据绑定实现原理是什么样的,如果让我们自己去实现一个这样的双向数据绑定要怎么做呢,本文就与大家分享一下Vue的绑定原理及其简单实现
飞码LowCode前端技术系列:如何便捷快速验证实现投产及飞码探索 | 京东云技术团队
本篇文章从数据中心,事件中心如何协议工作、不依赖环境对vue2.x、vue3.x都可以支持、投产页面问题定位三个方面进行分析。一、数据中心,事件中心设计飞码是数据驱动事件驱动的产品,考虑到飞码运行环境,飞码自己封装了store。数据中心:在同一个页面中可