Vue是数据驱动视图模式,数据变动后,会自动更新视图。开发很便利,不要手动管理视图更新。哪 Vue 是如何实现自动更新,也就是响应式的?vue
以原生 JS 为例,数据变化了须要手动获取 Dom 节点,而后使用相关 Api 去修改视图git
代码实现, 一共 373 行JS代码,包含Watcher/Observer的简单实现github
入口代码:数据结构
new Vue({
el: '#app',
data() {
return {
message: 'hello'
}
},
render(h) {
return h('div', null, this.message)
},
})
复制代码
渲染效果: 闭包
响应式更新:app
通常而言,对于基本类型的值是否变化,能够对比先后值是否相同。对于引用类型是否有变化,则可能须要递归判断属性是否都一致。异步
在 Vue 中,组件数据 data 是 Object 类型的,这样作的好处,我理解一是方便扩展属性、二是为了能方便对数据进行拦截、代理等。函数
针对 Object 类型的的数据,其相关key/value能够经过 数据属性/访问器属性 获取。二者能够是能够互换的: 性能
在Vue中定义的数据结构为 ui
data
函数的值会存储到
_data
私有属性中:
function proxy(target, sourceKey, key) {
Object.defineProperty(target, key, {
enumerable: true,
configurable: true,
get() {
return target[sourceKey][key]
},
set(val) {
target[sourceKey][key] = val
}
})
}
复制代码
借助 getter/setter 便可感知到数据变化,而自动触发视图更新作准备
Vue视图渲染的过程为: 模板 + 数据 -> 虚拟Dom -> Diff ... Dom操做 -> 真实Dom(渲染到页面中),这个过程能够很天然的使用数据。但数据不只包含视图展现数据、还会有一些视图不须要数据,若是每次检测到数据变化都从新执行一遍视图的渲染,这样可能形成极大的性能损耗。那如何才能识别哪些是视图所依赖的数据呢?
数据是在函数中引用的,故能够在访问数据时,记录当前执行的函数便可,整个思路以下:
访问器,执行闭包的保存的render函数,触发视图从新渲染 在Vue中实现,为了更好的性能(异步渲染,可能多处修改属性值)、更好的扩展性(属性可能多处被引用,须要自动更新、以及支持watch、compute属性等),引入了 watcher/observer/dep 来实现依赖收集以及自动更新。
经过 defineProperty 对数据属性进行拦截,再拦截的基础上 基于 JS 单线程原理进行依赖收集,数据变动时触发视图的从新渲染。