问题:如代码所示,我们在多次更新data属性,会不会触发多次dom diff计算和渲染,在更新data属性到dom渲染过程发生了什么事?

<template><div><div>{{title}}</div><div @click="refresh">更新</div></div>
</template><script>export default {data() {return {title: ''};},methods: {refresh() {this.title = '测试数据1';this.title = '测试数据2';this.title = '测试数据3';this.title = '测试数据4';this.title = '测试数据5';this.title = '测试数据6';}}};
</script>

一、了解Observer、Dep、Watcher

1、vue组件初始化

vue组件初始化的时候会执行_init函数,从而做了一些初始化处理,在处理不同阶段中调用不同的vue生命周期函数,例:breforeCreate、created等

Vue.prototype._init = function (options) {var vm = this;initEvents(vm);// 将render函数转化为vnodeinitRender(vm);// 调用beforeCreate生命周期函数callHook(vm, 'beforeCreate');initInjections(vm);// 初始化处理props、methods、data、computed、watchinitState(vm);initProvide(vm);// 调用created生命周期函数callHook(vm, 'created');....// 挂载组件到DOM树if (vm.$options.el) {vm.$mount(vm.$options.el);}
}

2、Observer

initState → initData → observe → new Observer(data) → Observer.walk(data) → defineReactive$$1(data, key) → Object.defineProperty(data, key, {get, set})
通过调用链可以发现在initData开始,由Observer开始对data每个key值进行set、get的拦截监听(利用Object.defineProperty),同时可以发现在defineReactive$$1中对每个key值的拦截监听都会创建一个Dep对象,在get的时候调用dep.depend(),在set的时候调用dep.notify()

function defineReactive$$1 (obj,key,val,customSetter,shallow
) {var dep = new Dep();// 对data的key进行set、get拦截Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter () {dep.depend();},set: function reactiveSetter (newVal) {dep.notify();}}
}

3、Dep

Dep对象主要将watcher对象维护在自己的属性中,同时也将自己加入到watcher中,在notify时候会调用watcher的update方法

var Dep = function Dep () {this.id = uid++;this.subs = [];
};// 将watcher加入到dep的subs数组中
Dep.prototype.addSub = function addSub (sub) {this.subs.push(sub);
};Dep.prototype.removeSub = function removeSub (sub) {remove(this.subs, sub);
};// 将dep加入到watcher的deps数组中、同时
Dep.prototype.depend = function depend () {if (Dep.target) {Dep.target.addDep(this);}
};// 遍历dep中watcher、调用他们update方法
Dep.prototype.notify = function notify () {var subs = this.subs.slice();for (var i = 0, l = subs.length; i < l; i++) {subs[i].update();}
};

4、Watcher

vm.$mount → mountComponent → new Watcher(vm, updateComponent)
由调用链在创建Watcher对象后,会将自己压入栈顶,等待触发data 属性getter时候,将dep和watcher对象互相绑定

// 挂载组件
function mountComponent (vm,el,hydrating
) {updateComponent = function () {// vm.render()执行render函数生成新节点vm._update(vm._render(), hydrating);};// 创建Watcher对象new Watcher(vm, updateComponent, noop, {before: function before () {if (vm._isMounted && !vm._isDestroyed) {callHook(vm, 'beforeUpdate');}}}, true);
}/************* Watcher函数 **********************/
var Watcher = function Watcher (vm,expOrFn,cb,options,isRenderWatcher
) {// 存储的dep数组this.deps = [];// 存储的dep idthis.depIds = new _Set();// 存储调用者传过来的updateComponentthis.expression = expOrFn.toString();if (typeof expOrFn === 'function') {this.getter = expOrFn;}this.value = this.lazy ? undefined : this.get();
}// watcher的get方法
Watcher.prototype.get = function get () {// 将当前watcher压栈pushTarget(this);value = this.getter.call(vm, vm);// 将当前watcher出栈popTarget();
}// 添加dep到Watcher对象属性中
Watcher.prototype.addDep = function addDep (dep) {var id = dep.id;if (!this.newDepIds.has(id)) {this.newDepIds.add(id);this.newDeps.push(dep);if (!this.depIds.has(id)) {// 将watcher对象添加到dep对象中dep.addSub(this);}}
};// Watcher对象update方法
Watcher.prototype.update = function update () {/* istanbul ignore else */if (this.lazy) {// 懒加载this.dirty = true;} else if (this.sync) {// 同步组件this.run();} else {// watcher队列queueWatcher(this);}
};// Watcher对象run方法
Watcher.prototype.run = function run () {if (this.active) {var value = this.get();if (value !== this.value ||// Deep watchers and watchers on Object/Arrays should fire even// when the value is the same, because the value may// have mutated.isObject(value) ||this.deep) {// set new valuevar oldValue = this.value;this.value = value;if (this.user) {try {this.cb.call(this.vm, value, oldValue);} catch (e) {handleError(e, this.vm, ("callback for watcher \"" + (this.expression) + "\""));}} else {this.cb.call(this.vm, value, oldValue);}}}
};

二、vue组件中数据更新会发生什么事情?

由于上面我们同步了一些关键信息,通过断点结合,可以看到整个调用过程
1、数据更新,我们首先会触发Data的set拦截,同时调用dep的notify方法。
2、遍历dep对象中的watcher数组,执行watcher的update方法。
3、在watcher的update函数中调用queueWatcher方法,并将自己作为入参。
4、在queueWatcher函数中,判断has map是否有当前watcher id,没有则将watcher存入queue队列,记录watcher id到has map中,调用nextTick方法;有则跳过这一步,等待异步刷新队列执行(异步刷新队列:flushSchedulerQueue)。
5、在nextTick中,将flushSchedulerQueue push进callbacks数组,执行timerFunc方法。
6、timerFunc中等待浏览器的微任务/宏任务回调时候遍历执行callbacks数组中的异步刷新队列方法flushSchedulerQueue。
7、在flushSchedulerQueue中,调用watcher的run方法。
8、在watcher的run中,调用watcher的get方法。
9、在watcher的get中,调用watcher的getter属性方法。
10、在Watcher对象初始化时候,getter就是mountComponent时候传入updateComponent方法。
11、执行updateComponent方法,会调用组件_update方法,传入当前组件_render函数返回值。
12、在_render函数中,获取当前组件data中的值(当前最新的值)。
13、在_update中,调用patch方法,传入新旧Vnode。
14、在patch中,调用patchVnode方法,开始diff比较虚拟dom树。

堆栈调用.png


http://www.taodudu.cc/news/show-2433754.html

相关文章:

  • Vue 2.6.13 源码解析(四) Observer、Dep、Watcher与订阅
  • dep指定版本 go_将 dep 更换为 go mod
  • DEP
  • DEP原理及关闭
  • 《Windows安全机制》之DEP(数据执行保护)
  • Go官方依赖包管理工具dep的安装及使用
  • 图扑软件网址
  • 图扑软件以轻量化建模构建智慧城市
  • 图扑软件 | 数字孪生智慧选煤厂
  • 图扑软件携手华为云再创合作共赢新局面
  • 方大九钢携手图扑软件:数字孪生智慧钢厂
  • ht for web(图扑)加载模型
  • 图扑案例合集丨用赛博朋克语言诠释数字孪生
  • 图扑软件数字孪生 SMT 产线,智能工业可视化管理
  • 图扑软件数字孪生挖掘机实现远程操控
  • 倾斜摄影技术构建 WebGIS 智慧展馆 | 图扑软件
  • TDengine在图扑工业物联网监控平台中的应用
  • 2021年图扑软件重点事件回顾
  • 图扑软件数字孪生微电网,部署源网荷储一体化平台事半功倍
  • 图扑数字孪生数据中心机房,助力产业绿色低碳转型
  • 图扑软件数字孪生民航飞联网,构建智慧民航新业态
  • 图扑 Web 可视化引擎在仿真分析领域的应用
  • 图扑软件基于钻孔数据的三维地质模型可视化
  • 图扑数字孪生智慧隧道,新基建带来新生活
  • 图扑软件构建源网荷储用体系 打造循环经济2.0版本
  • 智慧风电 | 图扑软件数字孪生风机设备,3D 可视化智能运维
  • 图扑软件 3D 组态编辑器,低代码零代码构建数字孪生工厂
  • 图扑软件数字孪生油气管道站,搭建油气运输管控平台
  • 图扑国风设计 3D 可视化 | 科技与文化碰撞炫酷”火花“
  • 图扑数字孪生智慧加油站,构建安全防护网

vue-Observe、Dep、Watcher相关推荐

  1. Vue数据响应式原理:Observe、Dep、Watcher

    在Vue中,数据响应式Observe是通过使用闭包来实现的.简单来说,就是利用了JavaScript中函数作用域链的特性,将数据对象以及相关的数据操作函数保存在闭包内部,从而达到对数据的监听.更新等操 ...

  2. Go:包管理工具GOPATH、vendor、dep 、go module

    目录 Go包管理工具:前言 GOPATH vendor.dep Go modules Module 文件 go mod命令 Go modules使用步骤: go module的文件下载后位置: Go包 ...

  3. OSCP、OSEP、OSWE、OSED四大认证对比,看这一篇就够了!

    OffSec团队认为:Defensive(防御)与Offensive(进攻)之间存在巨大差异. OffSec团队观点:在进攻安全领域,我们教导进攻是最好的防御,但同时我们也为防御者提供了公平的竞争环境 ...

  4. vue响应式系统--observe、watcher、dep

    Vue的响应式系统 Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是普通的JavaScript 对象,而当你修改它们时,视图会进行更新,这使得状态管理非常简单直接,我们可以只关注数据 ...

  5. Vue2双向绑定,Object.defineProperty、Observe、Compile、Watcher、Dep各显神通,相辅相成

    这个问题真的可以说是一个好问题,毕竟基本上面试时也总会被问到,一问双向绑定原理怎么回事儿啊?就说,用了Object.defineProperty()做得数据劫持,劫持了get()和set(),然后巴拉 ...

  6. vue取通过key取value_彻底理解Vue中的Watcher、Observer、Dep

    思考以下代码 new Vue({el: '#example',data(){return{obj:{a:1}}}, }) 当我们写下这行代码时,vue将我们在data内定义的obj对象进行依赖追踪. ...

  7. vue快速学习01、环境与常用属性标签

    vue快速学习01.环境与常用属性标签 1.MVVC MVVM 设计模式是由 Model (模型). View (视图)和 ViewModel (视图模型)三部分组成,是 MVC 设计模式的进化版,即 ...

  8. 前端面试题(HTML、JS、Vue、React、小程序)

    前端面试题 HTML && CSS HTML 1.Div 里面有个一个div ***** Q:有几种方法可以水平,垂直居中 2.doctype的作用 * 3.link标签和import ...

  9. web前端 vue、react、angular三大框架对比 与jquery的对比

    前端当前最火的三大框架当属vue.react以及angular了. 但是在做项目的时候,我们怎么去选择呢?  这里做一个比较,希望大家可以有一个比较清晰的认识. vue与react vue和react ...

  10. vue学习-v-if v-for优先级、data、key、diff算法、vue组件化、vue设计原则、组件模板只有一个根元素、MVC.MVP,MVVM

    1:v-if和v-for哪个优先级更高?如果两个同时出现,应该怎么优化得到更好的性能? //在vue页面中 同时使用v-for与v-if后,打印渲染函数. console.log(app.$optio ...

最新文章

  1. Vim实战指南(一):基础编辑命令
  2. css高级教程第一章笔记
  3. svn: E200033: database is locked, executing statement 'RELEASE   s0' 问题解决办法
  4. PHP正则表达式提取超链接及其标题
  5. thinkphp中join用法
  6. Coarse-Grained lock 粗粒度锁
  7. API和Web API(1)
  8. Service GIS
  9. size函数 matlab 含义,size()函数的使用
  10. echarts无数据时显示暂无数据或者用图片代替
  11. 设计模式(二):Facade和Adapter模式
  12. mysql下载与安装 win10 64位
  13. 系统分析和设计方法之用户界面设计
  14. omf多路径 oracle_Oracle数据库使用OMF来简化数据文件的管理
  15. VS2010如何安装MSComm控件
  16. Hadoop安装错误:Cannot set priority of secondarynamenode process : xxxxx
  17. Could not find a version that satisfies the requirement cryptography (from pymysql) (from versions:
  18. 【服务器数据恢复】Storwize系列存储raid5数据恢复案例
  19. 华为 博士 实习_如何看待华为招聘生物博士实习生?
  20. 腾讯地图类快递自动填写收发货地址功能

热门文章

  1. 主页被修改成httpwww.yy4000.cn等类似首页,无法更改,怎么办?
  2. 【linux】vi常用快捷键
  3. Unity3D 游戏摄像机的环绕与拉近
  4. IB选课指南及热门专业选课建议
  5. Deep Learning 学习笔记
  6. 普度大学计算机科学博士,Top15普渡大学计算机博士全奖录取
  7. 金蝶EAS系统,供应链,即时库存查询,库存查询SQL脚本
  8. javascript 纯前端实现汉字转拼音 —— pinyin-pro 库
  9. 华为USG6320做双线-基于源地址的策略路由
  10. 点赋网络:淘宝店铺DSR评分具体含义分析