面试问题:created
生命期中2次修改代码,会开启几回页面更新?
一、同步
先举一个简单同步
事例:
new Vue({
el: "#app",
template: `<div>
<div>{{count}}</div>
</div>`,
data() {
return {
count: 1,
}
},
created() {
this.count = 2;
this.count = 3;
},
});
在created
生命期中,根据this.count = 2
和this.count = 3
的形式将this.count
再次取值。
这儿立即抛出去回答:3D渲染一次。
为何?
这一与数据的响应式网站解决相关,首先看响应式网站解决的思路:
export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean
) {
// 关键:创建一个上传者案例
const dep = new Dep()
const property = Object.getOwnPropertyDescriptor(obj, key)
if (property && property.configurable === false) {
return
}
// cater for pre-defined getter/setters
const getter = property && property.get
const setter = property && property.set
if ((!getter || setter) && arguments.length === 2) {
val = obj[key]
}
let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
// 关键:开展现阶段已经计算出来的3D渲染Watcher的搜集
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
// #7981: for accessor properties without setter
if (getter && !setter) return
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
// 关键:当数据信息变化时,上传者案例dep会通告收集的watcher进行更新
dep.notify()
}
})
}
在数据响应式网站解决环节,会创建对象一个上传者dep
,同时通过Object.defineProperty
的方式为现阶段数据定义get
和set
函数公式。在形成虚似vNode
的时期,会开启get
函数中将进行现阶段已经计算出来的3D渲染Watcher
的搜集,这时,上传者dep
的subs
时会多一个3D渲染Watcher
案例。在数据发生变化情况下,会开启set
函数公式,通告上传者dep
中subs
里的watcher
进行更新。
对于数据修改会开启几回升级,就与当前上传者dep
的subs
中搜集了几回3D渲染watcher
相关了,再看一遍watcher
收集和created
实行中间顺序:
Vue.prototype._init = function (options) {
// ...
initState(vm);
// ...
callHook(vm, 'created');
// ...
if (vm.$options.el) {
vm.$mount(vm.$options.el);
}
}
我们都知道在initState(vm)
环节对数据进行响应式网站解决,可是这时上传者dep
的subs
或是空数组。当实行callHook(vm, 'created')
时,会实行this.count = 2
和this.count = 3
的思路,也确实会开启set
函数中的dep.notify
通告收集的watcher
进行更新。可是,这时dep
的subs
是空数组,等同于什么也没做。
只会在vm.$mount(vm.$options.el)
实施过程中,形成虚似vNode
的时候才能开展3D渲染Watcher
搜集,这时,dep
的subs
才不为空。最后,根据vm.$mount(vm.$options.el)
展开了界面的一次3D渲染,并没有由于this.count=2
或是this.count=3
而开启多余页面更新。
简而言之,便是created
钩子函数里的逻辑实行要在3D渲染watcher
搜集以前实施的,因此未造成由于数据变化而造成的页面更新。
二、多线程的
同步情景讲完了,咱们就举一个多线程的
事例:
new Vue({
el: "#app",
template: `<div>
<div>{{count}}</div>
</div>`,
data() {
return {
count: 1,
}
},
created() {
setTimeout(() => {
this.count = 2;
}, 0)
setTimeout(() => {
this.count = 3;
}, 0)
},
});
在created
生命期中,根据多线程的形式实行this.count = 2
和this.count = 3
的形式将this.count
再次取值。
这儿立即抛出去回答:初次3D渲染一次,由于数据变化所导致的页面更新2次。
为何?
这个我与eventLoop
事件循环体制相关了,我们都知道javascript
是一个单核实行的表达,在我们根据new Vue
创建对象的过程当中,会实行初始化方法this._init
方式,正式开始Vue
最底层的解决逻辑性。在遇到setTimeout
异步操作时,会把其送入到多线程序列
中来,等候现阶段同歩任务执行完之后再去多线程序列中取出队首原素开展实行。
现阶段例子中,在initState(vm)
环节对数据进行响应式网站解决。当实行callHook(vm, 'created')
时,会把this.count = 2
和this.count = 3
的思路送入到多线程序列等候实行。执行vm.$mount(vm.$options.el)
的过程中需要去形成虚似vNode
,从而开启get
函数的3D渲染Watcher
搜集,这时,dep
的subs
里就有了一个3D渲染watcher
。
等初次页面渲染完成以后,想去实行this.count=2
的思路,数据库的改动会开启set
函数中的dep.notify
,这时上传者dep
的subs
不为空,也会引起界面的升级。同样,this.count=3
会重新造成网页页面数据信息的更新。换句话说,初次3D渲染一次,由于this.count=2
和this.count=3
还会造成页面更新2次。
三、额外
假如我更改数值和data
中界定数值一致呢?
new Vue({
el: "#app",
template: `<div>
<div>{{count}}</div>
</div>`,
data() {
return { count: 1,
}
},
created() {
setTimeout(() => {
this.count = 1;
}, 0)
},
});
这时候,在开启set
的思路中,会当实行到if (newVal === value || (newVal !== newVal && value !== value)) { return }
的思路,不容易再执行到dep.notify
,这类场景中数据库的数据信息也不会造成界面的再度升级。
汇总
从生命期
created
和页面渲染的顺序,Object.defineProperty
开启get
和set
函数的原理,及其eventLoop
事件循环体制下手,来分析created
中2次数据修改会开启几回页面更新问题便会清楚许多。
声明:本文仅供个人学习使用,来源于互联网,本文有改动,本文遵循[BY-NC-SA]协议, 如有侵犯您的权益,请联系本站,本站将在第一时间删除。谢谢你