Vue深入響應(yīng)式原理

如何追蹤變化闰非?

把一個(gè)js對(duì)象傳遞給Vue實(shí)例的data選項(xiàng),Vue將遍歷此對(duì)象的所有屬性峭范,并通過(guò)<pre><code>Object.defineProperty</code></pre>把這些屬性轉(zhuǎn)化為setter/getter财松。也就是在實(shí)例初始化的過(guò)程中,Vue的內(nèi)部方法_proxy遍歷data中屬性的key纱控,并通過(guò)<pre><code>Object.defineProperty</code></pre>把這些屬性轉(zhuǎn)化為setter/getter辆毡,將data中的屬性代理到vm實(shí)例上。
用戶看不到getter/setter,但是在內(nèi)部Vue通過(guò)它們追蹤依賴甜害,在屬性被訪問(wèn)和修改的時(shí)候通知變化舶掖。
每個(gè)組件實(shí)例都有相應(yīng)的watcher實(shí)例對(duì)象,它在組件渲染過(guò)程中把屬性記錄為依賴尔店。之后當(dāng)依賴項(xiàng)的setter被調(diào)用時(shí)眨攘,會(huì)通知watcher重新計(jì)算主慰,從而使它關(guān)聯(lián)的組件得以跟新。

Vue.js源碼解析:深入響應(yīng)式原理

不在data上的屬性鲫售,Vue是沒(méi)有辦法檢測(cè)的.Vue不允許在已經(jīng)創(chuàng)建的實(shí)例上動(dòng)態(tài)添加根級(jí)響應(yīng)式屬性共螺,但是可以通過(guò)<pre><code>Vue.set(object, key ,value)</code></pre>方法將響應(yīng)屬性添加到嵌套的對(duì)象上。也可以使用vm.$set實(shí)例方法情竹,是全局Vue.set方法的別名藐不。 <pre><code>this.$set(this.object, key, value)</code></pre>
例子:

var app1 = new Vue({ el:'#example', data:{ test:{ } } }); app1.$set(app1.test, 'b', 2); console.log(app1.test); //是一個(gè)Object,并且值是b:2

但是下面的寫法不能得到期望效果:
app1.$set(app1.$data, 'b', 2); //undefined
因?yàn)椴辉试S動(dòng)態(tài)添加根級(jí)屬性鲤妥。
還可以使用Object.assign()擴(kuò)展原對(duì)象的屬性佳吞。
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

例子:

app1.$set(app1.test, 'b', 2); app1.test = Object.assign({}, app1.test, {'a':1, 'c':3}); console.log(app1.test); //Object的值有:a:1, b:2, c:3

知識(shí)擴(kuò)展:

VUEAngular都實(shí)現(xiàn)了雙向數(shù)據(jù)綁定拱雏,機(jī)制有不同棉安。

angular的雙向綁定是使用臟檢查機(jī)制實(shí)現(xiàn)的。
實(shí)現(xiàn)機(jī)制如下:
對(duì)于有可能引起數(shù)據(jù)變化的事件進(jìn)行封裝,每次這些事件被觸發(fā)時(shí)候,就對(duì)數(shù)據(jù)進(jìn)行一遍檢查如蚜,如果發(fā)現(xiàn)數(shù)據(jù)有所變化我衬,就進(jìn)行相應(yīng)的更新回調(diào)。但是某個(gè)事件觸發(fā)時(shí)候碳锈,需要檢查哪個(gè)數(shù)據(jù)呢?我們并不知道這個(gè)事件有可能導(dǎo)致變化的對(duì)應(yīng)數(shù)據(jù),因此要粗暴的將所有數(shù)據(jù)進(jìn)行完全檢查滥嘴。但是有時(shí)候某個(gè)數(shù)據(jù)改變了,并不止影響自己至耻,也有可能會(huì)影響到其他數(shù)據(jù)若皱。因此,如果一次完全檢查視作一個(gè)檢查周期尘颓,那我們至少要進(jìn)行兩個(gè)周期走触。第二個(gè)周期用來(lái)確認(rèn)前一遍的數(shù)據(jù)變動(dòng)中,是否引起了其他的數(shù)據(jù)變動(dòng)疤苹。如果第二遍周期也有變動(dòng)互广,那么就需要繼續(xù)進(jìn)行第三次檢查周期,直到兩次檢查的數(shù)據(jù)完全一致則停止卧土。(來(lái)自同學(xué)分享)


VUE數(shù)據(jù)劫持方式的核心是依賴與Object.defineProperty()惫皱。不得不說(shuō)這是個(gè)了不起的方法,就是它支撐起了vue的雙向綁定尤莺。
Object.defineProperty()可以利用getter和setter對(duì)對(duì)象的各個(gè)屬性進(jìn)行劫持旅敷,一旦set值,則數(shù)據(jù)變動(dòng)缝裁,此時(shí)通知觀察者扫皱,進(jìn)行回調(diào)更新足绅。
這種方式的核心組件有四點(diǎn):

  1. Observer :數(shù)據(jù)監(jiān)聽(tīng)器,對(duì)接數(shù)據(jù)韩脑,能夠?qū)?shù)據(jù)對(duì)象的所有屬性進(jìn)行監(jiān)聽(tīng)氢妈,如果監(jiān)聽(tīng)到數(shù)據(jù)有變動(dòng),可拿到最新值并通知訂閱者
  2. Compile:指令解析器段多,對(duì)接dom首量,對(duì)每個(gè)元素節(jié)點(diǎn)的指令進(jìn)行掃描和解析,根據(jù)指令模板替換數(shù)據(jù)进苍,以及綁定相應(yīng)的更新函數(shù)
  3. Watcher:連接Observer和Compile的橋梁加缘,能夠訂閱并收到每個(gè)屬性變動(dòng)的通知,執(zhí)行指令綁定的相應(yīng)回調(diào)函數(shù)觉啊,從而更新視圖拣宏。
  4. MVVM:入口函數(shù),整合以上三者
異步更新隊(duì)列:

首先要了解什么是事件循環(huán)杠人?
JavaScript 運(yùn)行機(jī)制詳解:再談Event Loop 這篇文章寫的很清晰勋乾。

可能你還沒(méi)有注意到,Vue異步執(zhí)行 DOM 更新嗡善。只要觀察到數(shù)據(jù)變化辑莫,Vue 將開啟一個(gè)隊(duì)列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)改變罩引。如果同一個(gè) watcher 被多次觸發(fā)各吨,只會(huì)一次推入到隊(duì)列中。這種在緩沖時(shí)去除重復(fù)數(shù)據(jù)對(duì)于避免不必要的計(jì)算和 DOM 操作上非常重要袁铐。然后揭蜒,在下一個(gè)的事件循環(huán)“tick”中,Vue 刷新隊(duì)列并執(zhí)行實(shí)際(已去重的)工作昭躺。Vue 在內(nèi)部嘗試對(duì)異步隊(duì)列使用原生的Promise.then和MutationObserver忌锯,如果執(zhí)行環(huán)境不支持,會(huì)采用setTimeout(fn, 0)代替领炫。

例如偶垮,當(dāng)你設(shè)置vm.someData = 'new value',該組件不會(huì)立即重新渲染帝洪。當(dāng)刷新隊(duì)列時(shí)似舵,組件會(huì)在事件循環(huán)隊(duì)列清空時(shí)的下一個(gè)“tick”更新。多數(shù)情況我們不需要關(guān)心這個(gè)過(guò)程葱峡,但是如果你想在 DOM 狀態(tài)更新后做點(diǎn)什么砚哗,這就可能會(huì)有些棘手。雖然 Vue.js 通常鼓勵(lì)開發(fā)人員沿著“數(shù)據(jù)驅(qū)動(dòng)”的方式思考砰奕,避免直接接觸 DOM蛛芥,但是有時(shí)我們確實(shí)要這么做提鸟。為了在數(shù)據(jù)變化之后等待 Vue 完成更新 DOM ,可以在數(shù)據(jù)變化之后立即使用Vue.nextTick(callback)仅淑。這樣回調(diào)函數(shù)在 DOM 更新完成后就會(huì)調(diào)用称勋。例如:
{{message}} var vm =new Vue({ el:'#example', data: { message:'123' } }) vm.message ='new message'// 更改數(shù)據(jù) vm.$el.textContent ==='new message'// false Vue.nextTick(function(){ vm.$el.textContent ==='new message'// true })

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市涯竟,隨后出現(xiàn)的幾起案子赡鲜,更是在濱河造成了極大的恐慌,老刑警劉巖庐船,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件银酬,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡筐钟,警方通過(guò)查閱死者的電腦和手機(jī)揩瞪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)盗棵,“玉大人壮韭,你說(shuō)我怎么就攤上這事北发∥埔颍” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵琳拨,是天一觀的道長(zhǎng)瞭恰。 經(jīng)常有香客問(wèn)我,道長(zhǎng)狱庇,這世上最難降的妖魔是什么惊畏? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮密任,結(jié)果婚禮上颜启,老公的妹妹穿的比我還像新娘。我一直安慰自己浪讳,他們只是感情好缰盏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著淹遵,像睡著了一般口猜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上透揣,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天济炎,我揣著相機(jī)與錄音,去河邊找鬼辐真。 笑死须尚,一個(gè)胖子當(dāng)著我的面吹牛崖堤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播耐床,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼倘感,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了咙咽?” 一聲冷哼從身側(cè)響起老玛,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钧敞,沒(méi)想到半個(gè)月后蜡豹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溉苛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年镜廉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愚战。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡娇唯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出寂玲,到底是詐尸還是另有隱情塔插,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布拓哟,位于F島的核電站想许,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏断序。R本人自食惡果不足惜流纹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望违诗。 院中可真熱鬧漱凝,春花似錦、人聲如沸诸迟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)亮蒋。三九已至扣典,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間慎玖,已是汗流浹背贮尖。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留趁怔,地道東北人湿硝。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓薪前,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親关斜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子示括,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1.響應(yīng)式原理 把一個(gè)普通對(duì)象傳給 Vue 實(shí)例作為它的 data 選項(xiàng),Vue.js 將遍歷它的屬性痢畜,用Obje...
    lmem閱讀 562評(píng)論 0 1
  • 一垛膝、如何追蹤變化 使用Object.defineProperty將傳入的屬性轉(zhuǎn)換為setter/getter。每個(gè)...
    芒果加奶閱讀 397評(píng)論 0 1
  • tip:實(shí)例創(chuàng)建之后添加新的屬性到實(shí)例上丁稀,不會(huì)觸發(fā)視圖更新 分解tip:new Vue() 生命周期created...
    coolheadedY閱讀 1,327評(píng)論 0 0
  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容吼拥,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,050評(píng)論 0 29
  • 1.安裝 可以簡(jiǎn)單地在頁(yè)面引入Vue.js作為獨(dú)立版本线衫,Vue即被注冊(cè)為全局變量凿可,可以在頁(yè)面使用了。 如果希望搭建...
    Awey閱讀 11,016評(píng)論 4 129