摘要:下面我們會(huì)向大家解釋清楚為什么這個(gè)這么重要,以及它和的響應(yīng)式數(shù)據(jù)流有什么關(guān)系。源碼前面鋪墊這么多就是希望大家能理解接下來要講的響應(yīng)式數(shù)據(jù)流??偨Y(jié)講到這里大家應(yīng)該都能夠明白的響應(yīng)式數(shù)據(jù)流是如何實(shí)現(xiàn)的。
Vue、React介紹
目前前端社區(qū)比較推崇的框架有Vue 和 React,公司內(nèi)部許多端都自發(fā)的將原有的老技術(shù)方案(widget + jQuery)遷移到 Vue / React上了。
我覺得Vue / React 有以下幾點(diǎn)優(yōu)勢
首先它們都有完整的組件化方案
virtual Dom (前端性能提升利器)
成熟的社區(qū)生態(tài)
介紹一個(gè)Vue例子上面的例子我們初始化了一個(gè)vue組件,當(dāng)我們改變這個(gè)組件的狀態(tài)時(shí),頁面的內(nèi)容也會(huì)隨之改變,這中間并不需要我們手動(dòng)的去操作頁面上的dom元素。
同時(shí)我們注意到Vue提供了一個(gè)語法糖 ——watch,這個(gè)就是我們今天要講的 Vue響應(yīng)式數(shù)據(jù)流的主角!代碼很簡單,就是組件的狀態(tài) name 改變的時(shí)候我們輸出一句話 “name change”。
下面我們會(huì)向大家解釋清楚為什么這個(gè) watch 這么重要,以及它和 Vue的響應(yīng)式數(shù)據(jù)流有什么關(guān)系。
Vue 和 React 都是前端的組件化框架,功能上大同小異,本質(zhì)上就是借助virtual Dom幫助開發(fā)者管理混亂的Dom,并提供給開發(fā)者像操作狀態(tài)機(jī)一樣操作頁面的能力。
但是Vue的virtual Dom 不是普通的 virtual Dom
Vue 2.0 的實(shí)現(xiàn)有與眾不同的地方。和 Vue 的響應(yīng)式系統(tǒng)結(jié)合在一起之后,它可以讓你不必做任何事就獲得完全優(yōu)化的重渲染。由于每個(gè)組件都會(huì)在渲染時(shí)追蹤其響應(yīng)依賴,所以系統(tǒng)精確地知道應(yīng)該何時(shí)重渲染、應(yīng)該重渲染哪些組件。不需要 shouldComponentUpdate,也不需要 immutable 數(shù)據(jù) - it just works . —— 尤雨溪
我們看一下第三方的性能分析:
除了性能,最大的優(yōu)勢是減輕了開發(fā)者的負(fù)擔(dān),開發(fā)者大多數(shù)情況下不需要依賴 shouldComponentUpdate,也不需要依賴 immutable 數(shù)據(jù)去判斷組件是否需要重新渲染,Vue會(huì)幫你做好這件事。
舉個(gè)例子來說明這兩個(gè)的virtual dom的不同之處:
預(yù)備知識(shí):Object.defineProperty 與 訂閱發(fā)布設(shè)計(jì)模式 Object.defineProperty開發(fā)者就像一個(gè)老師,Vue和React這兩個(gè)學(xué)生要做的事就是根據(jù)老師給出的長寬畫出對(duì)應(yīng)的長方形。每當(dāng)老師改變給出的長和寬時(shí),Vue能夠自己發(fā)現(xiàn)長和寬變沒變,需不需要重新畫;React則需要老師告訴它長和寬變了,需要重新畫了。
JavaScript 提供一個(gè)非常強(qiáng)大的方法 Object.defineProperty,它可以定義當(dāng)某一個(gè)值訪問和賦值時(shí)會(huì)先執(zhí)行自定義的鉤子方法。
一個(gè)簡單的Object.defineProperty例子var obj = {}; var initValue = "hello"; Object.defineProperty(obj,"newKey",{ get:function (){ //當(dāng)獲取值的時(shí)候觸發(fā)的函數(shù) return initValue; }, set:function (value){ //當(dāng)設(shè)置值的時(shí)候觸發(fā)的函數(shù),設(shè)置的新值通過參數(shù)value拿到 console.log(value) initValue = value; } }); //獲取值 console.log( obj.newKey ); //hello //設(shè)置值 obj.newKey = "change value"; //change value
這個(gè)方法給予JavaScript開發(fā)一種面向切面編程的能力,使用該方法我們能夠隱式、自然的控制屬性的訪問和賦值。
訂閱發(fā)布設(shè)計(jì)模式訂閱發(fā)布是一個(gè)非常常見的設(shè)計(jì)模式,原理也非常簡單就是訂閱者訂閱信息,然后發(fā)布者發(fā)布信息通知訂閱者更新。
Vue 源碼前面鋪墊這么多就是希望大家能理解接下來要講的響應(yīng)式數(shù)據(jù)流。
Vue的初始化
如上圖,Vue的初始化會(huì)執(zhí)行一系列的方法,這里我們主要介紹Vue的initState 方法。
prop和data都是組件的屬性,prop通常上是父組件傳遞下來的,data是組件自身定義的,Vue不推薦你去改組件傳遞下來的prop,因?yàn)槟菢訒?huì)帶來不必要的復(fù)雜度。
Prop和data 的最終歸宿都是遞歸執(zhí)行 defineReactive方法。
那defineReactive方法做了什么呢?
defineReactive會(huì)用 Object.defineProperty將組件的每個(gè)屬性都包裝一下,這樣誰訪問了這些屬性,誰重新賦值了這些屬性我們都能追蹤到了。
Vue里面有一個(gè) Observe類,所有的prop子屬性和data本身都會(huì)帶有一個(gè)Observer對(duì)象,Observer的構(gòu)造函數(shù)
在控制臺(tái)我們可以看到每個(gè)屬性下都有__ob__,這說明這個(gè)屬性已經(jīng)被包裝成 Observer對(duì)象了,所以的訪問和賦值都能給追蹤到,這里面也保存著所有訂閱該Observer的訂閱者Watcher。
我們看一下Watcher的構(gòu)造函數(shù)
Watcher支持 watch 一個(gè)表達(dá)式或者是一個(gè)方法。Watcher在構(gòu)造的時(shí)候會(huì)先獲取一次expOrFn的值,下面我們把expOrFn稱為Watcher的Getter。
Dep還有一個(gè)關(guān)鍵的類是Dep,這個(gè)類會(huì)幫助我們的屬性記錄下所有的Watcher,每個(gè)屬性都有自己的Dep實(shí)例,同時(shí)Vue的Watcher訪問的屬性的時(shí)候 Dep會(huì)作為一個(gè)全局變量將自身的target屬性指向訪問的Wathcer。會(huì)執(zhí)行下面的方法
同時(shí)我們?cè)倩貋砜?defineReactive這個(gè)重要的方法
當(dāng)Watcher訪問組件的屬性時(shí),通過Dep.target,Vue可以知道是Watcher訪問的, 這樣當(dāng)Vue自己的Watcher訪問屬性的時(shí)候會(huì)被記錄成訂閱者,而我們?cè)L問的時(shí)候Vue不會(huì)執(zhí)行多余的代碼。這是一個(gè)很精妙的設(shè)計(jì),將Object.defineProperty 與 訂閱發(fā)布設(shè)計(jì)模式結(jié)合起來了。
看一下整個(gè)的流程圖
理解了以上Vue是如何將Object.defineProperty 與 訂閱發(fā)布設(shè)計(jì)模式結(jié)合起來的,然后我們?cè)倥e一反三:Vue的render函數(shù)如果就是 Watcher 的 expOrFn會(huì)怎么樣?
回到Vue的源碼里:
這里的 vm._render就是 render函數(shù)的一個(gè)封裝,我們可以看到本質(zhì)上:Vue的render函數(shù)就是 Watcher 的 expOrFn。那初始化的時(shí)候我們會(huì)先執(zhí)行一邊 render函數(shù),在執(zhí)行render函數(shù)的過程中訪問了哪些 組件的屬性,Vue都會(huì)用上面的提到的方法幫我們把依賴記錄下來。所以當(dāng)這個(gè)屬性變化的時(shí)候,自然而然,就像文章開頭的watch一樣,我們會(huì)重新render一次,(開頭的例子是輸出“name change”)。
總結(jié)講到這里大家應(yīng)該都能夠明白Vue的響應(yīng)式數(shù)據(jù)流是如何實(shí)現(xiàn)的。同時(shí)我們能夠發(fā)現(xiàn)Vue提供給我們的許多語法糖都是同樣的道理,比如Vue的computer就是將computer函數(shù)作為Watcher的expOrFn。
希望大家在理解Vue響應(yīng)式數(shù)據(jù)流的基礎(chǔ)上能夠更加自信、靈活和穩(wěn)健的使用這個(gè)優(yōu)秀的框架。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/81040.html
摘要:在看的實(shí)現(xiàn)之前。實(shí)現(xiàn)響應(yīng)式的關(guān)鍵有三個(gè)遍歷中的屬性。在方法中設(shè)置核心數(shù)據(jù)劫持每個(gè)屬性都有一個(gè)自己的消息訂閱起用于訂制該屬性上的所有觀察者觀察者,通過實(shí)現(xiàn)對(duì)響應(yīng)屬性的監(jiān)聽觀察。觀察得到結(jié)果后,主動(dòng)觸發(fā)自己的回調(diào)可以去看看的這三部分源碼。 本來vue的響應(yīng)式應(yīng)該才是重中之重。但是網(wǎng)上的文章很多很多。在看computed的實(shí)現(xiàn)之前。肯定還是要把vue的響應(yīng)式如何實(shí)現(xiàn)好好看一下。或者說兩者根本...
寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【Vue原理】Props - 源碼版 今天記錄 Props 源碼流程,哎,這東西,就算是研究過了,也真是會(huì)隨著時(shí)間慢慢忘記的。 幸好我做...
摘要:先說遍歷,很簡單,如下行左右代碼就足夠遍歷一個(gè)對(duì)象了遇到普通數(shù)據(jù)屬性,直接處理,遇到對(duì)象,遍歷屬性之后遞歸進(jìn)去處理屬性,遇到數(shù)組,遞歸進(jìn)去處理數(shù)組元素。這樣改進(jìn)之后我就不需要對(duì)數(shù)組元素進(jìn)行響應(yīng)式處理,只是遇到數(shù)組的時(shí)候把數(shù)組的方法變異即可。 用了Vue很久了,最近決定系統(tǒng)性的看看Vue的源碼,相信看源碼的同學(xué)不在少數(shù),但是看的時(shí)候卻發(fā)現(xiàn)挺有難度,Vue雖然足夠精簡,但是怎么說現(xiàn)在也有1...
摘要:寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請(qǐng)點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號(hào)也可以吧如果你覺得排版難看,請(qǐng)點(diǎn)擊下面公眾號(hào) 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基...
摘要:當(dāng)東西發(fā)售時(shí),就會(huì)打你的電話通知你,讓你來領(lǐng)取完成更新。其中涉及的幾個(gè)步驟,按上面的例子來轉(zhuǎn)化一下你買東西,就是你要使用數(shù)據(jù)你把電話給老板,電話就是你的,用于通知老板記下電話在電話本,就是把保存在中。剩下的步驟屬于依賴更新 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【...
閱讀 3237·2021-11-02 14:44
閱讀 3737·2021-09-02 15:41
閱讀 1679·2019-08-29 16:57
閱讀 1799·2019-08-26 13:38
閱讀 3308·2019-08-23 18:13
閱讀 2119·2019-08-23 15:41
閱讀 1681·2019-08-23 14:24
閱讀 3039·2019-08-23 14:03