vue面試created中兩次數(shù)據(jù)修改會(huì)觸發(fā)幾次頁面更新詳解
面試題:
created
生命周期中兩次修改數(shù)據(jù),會(huì)觸發(fā)幾次頁面更新?
一、同步的
先舉個(gè)簡(jiǎn)單的同步的例子:
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
重新賦值。
這里直接拋出答案:渲染一次。
為什么?
這個(gè)與數(shù)據(jù)的響應(yīng)式處理有關(guān),先看響應(yīng)式處理的邏輯:
export function defineReactive ( obj: Object, key: string, val: any, customSetter?: ?Function, shallow?: boolean ) { // 重點(diǎn):創(chuàng)建一個(gè)發(fā)布者實(shí)例 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) { // 重點(diǎn):進(jìn)行當(dāng)前正在計(jì)算的渲染W(wǎng)atcher的收集 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) // 重點(diǎn):當(dāng)數(shù)據(jù)發(fā)生變化時(shí),發(fā)布者實(shí)例dep會(huì)通知收集到的watcher進(jìn)行更新 dep.notify() } }) }
在數(shù)據(jù)響應(yīng)式處理階段,會(huì)實(shí)例化一個(gè)發(fā)布者dep
,并且通過Object.defineProperty
的方式為當(dāng)前數(shù)據(jù)定義get
和set
函數(shù)。在生成虛擬vNode
的階段,會(huì)觸發(fā)get
函數(shù)中會(huì)進(jìn)行當(dāng)前正在計(jì)算的渲染Watcher
的收集,此時(shí),發(fā)布者dep
的subs
中會(huì)多一個(gè)渲染Watcher
實(shí)例。在數(shù)據(jù)發(fā)生變化的時(shí)候,會(huì)觸發(fā)set
函數(shù),通知發(fā)布者dep
中subs
中的watcher
進(jìn)行更新。
至于數(shù)據(jù)修改會(huì)觸發(fā)幾次更新,就與當(dāng)前發(fā)布者dep
的subs
中收集了幾次渲染watcher
有關(guān)了,再看watcher
收集和created
執(zhí)行之間的順序:
Vue.prototype._init = function (options) { // ... initState(vm); // ... callHook(vm, 'created'); // ... if (vm.$options.el) { vm.$mount(vm.$options.el); } }
我們知道在initState(vm)
階段對(duì)數(shù)據(jù)進(jìn)行響應(yīng)式處理,但是此時(shí)發(fā)布者dep
的subs
還是空數(shù)組。當(dāng)執(zhí)行callHook(vm, 'created')
的時(shí)候,會(huì)執(zhí)行this.count = 2
和this.count = 3
的邏輯,也的確會(huì)觸發(fā)set
函數(shù)中的dep.notify
通知收集到的watcher
進(jìn)行更新。但是,此時(shí)dep
的subs
是空數(shù)組,相當(dāng)于啥也沒做。
只有在vm.$mount(vm.$options.el)
執(zhí)行過程中,生成虛擬vNode
的時(shí)候才會(huì)進(jìn)行渲染Watcher
收集,此時(shí),dep
的subs
才不為空。最終,通過vm.$mount(vm.$options.el)
進(jìn)行了頁面的一次渲染,并未因?yàn)?code>this.count=2或者this.count=3
而觸發(fā)多余的頁面更新。
簡(jiǎn)言之,就是created
鉤子函數(shù)內(nèi)的邏輯的執(zhí)行是在渲染watcher
收集之前執(zhí)行的,所以未引起因?yàn)閿?shù)據(jù)變化而導(dǎo)致的頁面更新。
二、異步的
同步的場(chǎng)景說完了,我們?cè)倥e個(gè)異步的例子:
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
生命周期中,通過異步的方式執(zhí)行this.count = 2
和this.count = 3
的方式將this.count
重新賦值。
這里直接拋出答案:首次渲染一次,因?yàn)閿?shù)據(jù)變化導(dǎo)致的頁面更新兩次。
為什么?
這個(gè)就與eventLoop
事件循環(huán)機(jī)制有關(guān)了,我們知道javascript
是一個(gè)單線程執(zhí)行的語言,當(dāng)我們通過new Vue
實(shí)例化的過程中,會(huì)執(zhí)行初始化方法this._init
方法,開始了Vue
底層的處理邏輯。當(dāng)遇到setTimeout
異步操作時(shí),會(huì)將其推入到異步隊(duì)列中去,等待當(dāng)前同步任務(wù)執(zhí)行完以后再去異步隊(duì)列中取出隊(duì)首元素進(jìn)行執(zhí)行。
當(dāng)前例子中,在initState(vm)
階段對(duì)數(shù)據(jù)進(jìn)行響應(yīng)式處理。當(dāng)執(zhí)行callHook(vm, 'created')
的時(shí)候,會(huì)將this.count = 2
和this.count = 3
的邏輯推入到異步隊(duì)列等待執(zhí)行。繼續(xù)執(zhí)行vm.$mount(vm.$options.el)
的過程中會(huì)去生成虛擬vNode
,進(jìn)而觸發(fā)get
函數(shù)的渲染Watcher
收集,此時(shí),dep
的subs
中就有了一個(gè)渲染watcher
。
等首次頁面渲染完成以后,會(huì)去執(zhí)行this.count=2
的邏輯,數(shù)據(jù)的修改會(huì)觸發(fā)set
函數(shù)中的dep.notify
,此時(shí)發(fā)布者dep
的subs
不為空,會(huì)引起頁面的更新。同理,this.count=3
會(huì)再次引起頁面數(shù)據(jù)的更新。也就是說,首次渲染一次,因?yàn)?code>this.count=2和this.count=3
還會(huì)導(dǎo)致頁面更新兩次。
三、附加
如果我改變的值和data
中定義的值一致呢?
new Vue({ el: "#app", template: `<div> <div>{{count}}</div> </div>`, data() { return { count: 1, } }, created() { setTimeout(() => { this.count = 1; }, 0) }, });
這個(gè)時(shí)候,在觸發(fā)set
的邏輯中,會(huì)當(dāng)執(zhí)行到if (newVal === value || (newVal !== newVal && value !== value)) { return }
的邏輯,不會(huì)再執(zhí)行到dep.notify
,這種場(chǎng)景下數(shù)據(jù)的數(shù)據(jù)也不會(huì)引起頁面的再次更新。
總結(jié)
從生命周期created
和頁面渲染的先后順序,Object.defineProperty
觸發(fā)get
和set
函數(shù)的機(jī)理,以及eventLoop
事件循環(huán)機(jī)制入手,去分析created
中兩次數(shù)據(jù)修改會(huì)觸發(fā)幾次頁面更新的問題就會(huì)清晰很多。
以上就是vue面試created中兩次數(shù)據(jù)修改會(huì)觸發(fā)幾次頁面更新詳解的詳細(xì)內(nèi)容,更多關(guān)于vue created數(shù)據(jù)修改頁面更新的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue獲取DOM元素并設(shè)置屬性的兩種實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄獀ue獲取DOM元素并設(shè)置屬性的兩種實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09Vue做一個(gè)簡(jiǎn)單的隨機(jī)點(diǎn)名冊(cè)
這篇文章主要介紹的是如何用Vue做一個(gè)簡(jiǎn)單的隨機(jī)點(diǎn)名冊(cè),主要是做個(gè)簡(jiǎn)單的點(diǎn)名器,不做樣式,需要的朋友可以參考一下,希望對(duì)你有所幫助2021-12-12vue頁面離開后執(zhí)行函數(shù)的實(shí)例
下面小編就為大家分享一篇vue頁面離開后執(zhí)行函數(shù)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-03-03vue mounted()函數(shù)中無法定義初始化樣式的原因分析
這篇文章主要介紹了vue mounted()函數(shù)中無法定義初始化樣式的原因分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03VUE v-model表單數(shù)據(jù)雙向綁定完整示例
這篇文章主要介紹了VUE v-model表單數(shù)據(jù)雙向綁定,結(jié)合完整實(shí)例形式分析了vue.js實(shí)現(xiàn)表單數(shù)據(jù)雙向綁定相關(guān)操作技巧,需要的朋友可以參考下2019-01-01vue使用高德地圖實(shí)現(xiàn)添加點(diǎn)標(biāo)記和獲取點(diǎn)擊位置信息的示例代碼
這篇文章主要介紹了vue使用高德地圖實(shí)現(xiàn)添加點(diǎn)標(biāo)記和獲取點(diǎn)擊位置信息的示例代碼,文中補(bǔ)充介紹了高德vue-amap使用(一)標(biāo)記點(diǎn)位獲取地址及經(jīng)緯度,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2024-01-01vue中created、watch和computed的執(zhí)行順序詳解
由于vue的雙向數(shù)據(jù)綁定,自動(dòng)更新數(shù)據(jù)的機(jī)制,在數(shù)據(jù)變化后,對(duì)此數(shù)據(jù)依賴?的所有數(shù)據(jù),watch事件都會(huì)被更新、觸發(fā),下面這篇文章主要給大家介紹了關(guān)于vue中created、watch和computed的執(zhí)行順序,需要的朋友可以參考下2022-11-11