资讯专栏INFORMATION COLUMN

源码解析 —— Vue的响应式数据流

LuDongWei / 2155人阅读

摘要:下面我们会向大家解释清楚为什么这个这么重要,以及它和的响应式数据流有什么关系。源码前面铺垫这么多就是希望大家能理解接下来要讲的响应式数据流。总结讲到这里大家应该都能够明白的响应式数据流是如何实现的。

Vue、React介绍

目前前端社区比较推崇的框架有Vue 和 React,公司内部许多端都自发的将原有的老技术方案(widget + jQuery)迁移到 Vue / React上了。
我觉得Vue / React 有以下几点优势

首先它们都有完整的组件化方案

virtual Dom (前端性能提升利器)

成熟的社区生态

介绍一个Vue例子

上面的例子我们初始化了一个vue组件,当我们改变这个组件的状态时,页面的内容也会随之改变,这中间并不需要我们手动的去操作页面上的dom元素。

同时我们注意到Vue提供了一个语法糖 ——watch,这个就是我们今天要讲的 Vue响应式数据流的主角!代码很简单,就是组件的状态 name 改变的时候我们输出一句话 “name change”。
下面我们会向大家解释清楚为什么这个 watch 这么重要,以及它和 Vue的响应式数据流有什么关系。

Vue的响应式数据流的优势在哪?

Vue 和 React 都是前端的组件化框架,功能上大同小异,本质上就是借助virtual Dom帮助开发者管理混乱的Dom,并提供给开发者像操作状态机一样操作页面的能力。

但是Vue的virtual Dom 不是普通的 virtual Dom

Vue 2.0 的实现有与众不同的地方。和 Vue 的响应式系统结合在一起之后,它可以让你不必做任何事就获得完全优化的重渲染。由于每个组件都会在渲染时追踪其响应依赖,所以系统精确地知道应该何时重渲染、应该重渲染哪些组件。不需要 shouldComponentUpdate,也不需要 immutable 数据 - it just works . —— 尤雨溪

我们看一下第三方的性能分析:

除了性能,最大的优势是减轻了开发者的负担,开发者大多数情况下不需要依赖 shouldComponentUpdate,也不需要依赖 immutable 数据去判断组件是否需要重新渲染,Vue会帮你做好这件事。

举个例子来说明这两个的virtual dom的不同之处:

开发者就像一个老师,Vue和React这两个学生要做的事就是根据老师给出的长宽画出对应的长方形。每当老师改变给出的长和宽时,Vue能够自己发现长和宽变没变,需不需要重新画;React则需要老师告诉它长和宽变了,需要重新画了。

预备知识:Object.defineProperty 与 订阅发布设计模式 Object.defineProperty

JavaScript 提供一个非常强大的方法 Object.defineProperty,它可以定义当某一个值访问和赋值时会先执行自定义的钩子方法。

一个简单的Object.defineProperty例子
var obj = {};
var initValue = "hello";
Object.defineProperty(obj,"newKey",{
    get:function (){
        //当获取值的时候触发的函数
        return initValue;    
    },
    set:function (value){
        //当设置值的时候触发的函数,设置的新值通过参数value拿到
        console.log(value)
        initValue = value;
    }
});
//获取值
console.log( obj.newKey );  //hello
//设置值
obj.newKey = "change value"; //change value

这个方法给予JavaScript开发一种面向切面编程的能力,使用该方法我们能够隐式、自然的控制属性的访问和赋值。

订阅发布设计模式

订阅发布是一个非常常见的设计模式,原理也非常简单就是订阅者订阅信息,然后发布者发布信息通知订阅者更新。

Vue 源码

前面铺垫这么多就是希望大家能理解接下来要讲的响应式数据流。

Vue的初始化


如上图,Vue的初始化会执行一系列的方法,这里我们主要介绍Vue的initState 方法。
prop和data都是组件的属性,prop通常上是父组件传递下来的,data是组件自身定义的,Vue不推荐你去改组件传递下来的prop,因为那样会带来不必要的复杂度。

Observer

Prop和data 的最终归宿都是递归执行 defineReactive方法。

那defineReactive方法做了什么呢?

defineReactive会用 Object.defineProperty将组件的每个属性都包装一下,这样谁访问了这些属性,谁重新赋值了这些属性我们都能追踪到了。
Vue里面有一个 Observe类,所有的prop子属性和data本身都会带有一个Observer对象,Observer的构造函数

在控制台我们可以看到每个属性下都有__ob__,这说明这个属性已经被包装成 Observer对象了,所以的访问和赋值都能给追踪到,这里面也保存着所有订阅该Observer的订阅者Watcher。

Watcher

我们看一下Watcher的构造函数

Watcher支持 watch 一个表达式或者是一个方法。Watcher在构造的时候会先获取一次expOrFn的值,下面我们把expOrFn称为Watcher的Getter。

Dep

还有一个关键的类是Dep,这个类会帮助我们的属性记录下所有的Watcher,每个属性都有自己的Dep实例,同时Vue的Watcher访问的属性的时候 Dep会作为一个全局变量将自身的target属性指向访问的Wathcer。会执行下面的方法

同时我们再回来看 defineReactive这个重要的方法

当Watcher访问组件的属性时,通过Dep.target,Vue可以知道是Watcher访问的, 这样当Vue自己的Watcher访问属性的时候会被记录成订阅者,而我们访问的时候Vue不会执行多余的代码。这是一个很精妙的设计,将Object.defineProperty 与 订阅发布设计模式结合起来了。
看一下整个的流程图

Vue的render函数就是 Watcher 的 expOrFn

理解了以上Vue是如何将Object.defineProperty 与 订阅发布设计模式结合起来的,然后我们再举一反三:Vue的render函数如果就是 Watcher 的 expOrFn会怎么样?
回到Vue的源码里:

这里的 vm._render就是 render函数的一个封装,我们可以看到本质上:Vue的render函数就是 Watcher 的 expOrFn。那初始化的时候我们会先执行一边 render函数,在执行render函数的过程中访问了哪些 组件的属性,Vue都会用上面的提到的方法帮我们把依赖记录下来。所以当这个属性变化的时候,自然而然,就像文章开头的watch一样,我们会重新render一次,(开头的例子是输出“name change”)。

总结

讲到这里大家应该都能够明白Vue的响应式数据流是如何实现的。同时我们能够发现Vue提供给我们的许多语法糖都是同样的道理,比如Vue的computer就是将computer函数作为Watcher的expOrFn。
希望大家在理解Vue响应式数据流的基础上能够更加自信、灵活和稳健的使用这个优秀的框架。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81040.html

相关文章

  • vue源码解析系列-compute实现机制

    摘要:在看的实现之前。实现响应式的关键有三个遍历中的属性。在方法中设置核心数据劫持每个属性都有一个自己的消息订阅起用于订制该属性上的所有观察者观察者,通过实现对响应属性的监听观察。观察得到结果后,主动触发自己的回调可以去看看的这三部分源码。 本来vue的响应式应该才是重中之重。但是网上的文章很多很多。在看computed的实现之前。肯定还是要把vue的响应式如何实现好好看一下。或者说两者根本...

    Lsnsh 评论0 收藏0
  • Vue原理】Props - 源码

    写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】Props - 源码版 今天记录 Props 源码流程,哎,这东西,就算是研究过了,也真是会随着时间慢慢忘记的。 幸好我做...

    light 评论0 收藏0
  • Vue源码详细解析:transclude,compile,link,依赖,批处理...一网打尽,全解

    摘要:先说遍历,很简单,如下行左右代码就足够遍历一个对象了遇到普通数据属性,直接处理,遇到对象,遍历属性之后递归进去处理属性,遇到数组,递归进去处理数组元素。这样改进之后我就不需要对数组元素进行响应式处理,只是遇到数组的时候把数组的方法变异即可。 用了Vue很久了,最近决定系统性的看看Vue的源码,相信看源码的同学不在少数,但是看的时候却发现挺有难度,Vue虽然足够精简,但是怎么说现在也有1...

    yy736044583 评论0 收藏0
  • Vue原理】Props - 白话版

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧如果你觉得排版难看,请点击下面公众号 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基...

    Carl 评论0 收藏0
  • Vue原理】依赖收集 - 源码版之基本数据类型

    摘要:当东西发售时,就会打你的电话通知你,让你来领取完成更新。其中涉及的几个步骤,按上面的例子来转化一下你买东西,就是你要使用数据你把电话给老板,电话就是你的,用于通知老板记下电话在电话本,就是把保存在中。剩下的步骤属于依赖更新 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【...

    VincentFF 评论0 收藏0

发表评论

0条评论

LuDongWei

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<