vue2vue3響應(yīng)式原理(vue的響應(yīng)原理)
今天給各位分享vue2vue3響應(yīng)式原理的知識,其中也會對vue的響應(yīng)原理進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧!
本文目錄一覽:
Vue3.0 響應(yīng)式原理
Vue3 使用 Proxy 對象重寫響應(yīng)式系統(tǒng),這個系統(tǒng)主要有以下幾個函數(shù)來組合完成的:
1、reactive:
接收一個參數(shù),判斷這參數(shù)是否是對象。不是對象則直接返回這個參數(shù),不做響應(yīng)式處理
創(chuàng)建攔截器對象 handler, 設(shè)置 get/set/deleteProperty
get
收集依賴(track)
返回當(dāng)前 key 的值。
如果當(dāng)前 key 的值是對象,則為當(dāng)前 key 的對象創(chuàng)建攔截器 handler, 設(shè)置 get/set/deleteProperty
如果當(dāng)前的 key 的值不是對象,則返回當(dāng)前 key 的值
set
設(shè)置的新值和老值不相等時,更新為新值,并觸發(fā)更新(trigger)
deleteProperty
當(dāng)前對象有這個 key 的時候,刪除這個 key 并觸發(fā)更新(trigger)
返回 Proxy 對象
2、effect: 接收一個函數(shù)作為參數(shù)。作用是:訪問響應(yīng)式對象屬性時去收集依賴
3、track:
接收兩個參數(shù):target 和 key
如果沒有 activeEffect,則說明沒有創(chuàng)建 effect 依賴
如果有 activeEffect,則去判斷 WeakMap 集合中是否有 target 屬性,
WeakMap 集合中沒有 target 屬性,則 set(target, (depsMap = new Map()))
WeakMap 集合中有 target 屬性,則判斷 target 屬性的 map 值的 depsMap 中是否有 key 屬性
depsMap 中沒有 key 屬性,則 set(key, (dep = new Set()))
depsMap 中有 key 屬性,則添加這個 activeEffect
4、trigger:
判斷 WeakMap 中是否有 target 屬性
WeakMap 中沒有 target 屬性,則沒有 target 相應(yīng)的依賴
WeakMap 中有 target 屬性,則判斷 target 屬性的 map 值中是否有 key 屬性,有的話循環(huán)觸發(fā)收集的 effect()
聊一聊 Vue3 中響應(yīng)式原理
Vue.js 3.0 "One Piece" 正式發(fā)布已經(jīng)有一段時間了,真可謂是千呼萬喚始出來?。?/p>
相比于 Vue2.x , Vue3.0 在新的版本中提供了更好的性能、更小的捆綁包體積、更好的 TypeScript 集成、用于處理大規(guī)模用例的新 API 。
在發(fā)布之前,尤大大就已經(jīng)聲明了響應(yīng)式方面將采用 Proxy 對于之前的 Object.defineProperty 進(jìn)行改寫。其主要目的就是彌補(bǔ) Object.defineProperty 自身的一些缺陷,例如無法檢測到對象屬性的新增或者刪除,不能監(jiān)聽數(shù)組的變化等。
而 Vue3 采用了新的 Proxy 實現(xiàn)數(shù)據(jù)讀取和設(shè)置攔截,不僅彌補(bǔ)了之前 Vue2 中 Object.defineProperty 的缺陷,同時也帶來了性能上的提升。
今天,我們就來盤一盤它,看看 Vue3 中響應(yīng)式是如何實現(xiàn)的。
The Proxy object enables you to create a proxy for another object, which can intercept and redefine fundamental operations for that object. MDN
Proxy - 代理,顧名思義,就是在要訪問的對象之前增加一個中間層,這樣就不直接訪問對象,而是通過中間層做一個中轉(zhuǎn),通過操作代理對象,來實現(xiàn)修改目標(biāo)對象。
關(guān)于 Proxy 的更多的知識,可以參考我之前的一篇文章 —— 初探 Vue3.0 中的一大亮點——Proxy ! ,這里我就不在贅述。
Vue3 中響應(yīng)式核心方法就是 reactive 和 effect , 其中 reactive 方法是負(fù)責(zé)將數(shù)據(jù)變成響應(yīng)式, effect 方法的作用是根據(jù)數(shù)據(jù)變化去更新視圖或調(diào)用函數(shù),與 react 中的 useEffect 有點類似~
其大概用法如下:
默認(rèn)會執(zhí)行一次,打印 Hello , 之后更改了 data.name 的值后,會在觸發(fā)執(zhí)行一次,打印 World 。
我們先看看 reactive 方法的實現(xiàn)~
reactive.js
首先應(yīng)該明確,我們應(yīng)該導(dǎo)出一個 reactive 方法,該方法有一個參數(shù) target ,目的就是將 target 變成響應(yīng)式對象,因此返回值就是一個響應(yīng)式對象。
reactive 方法基本結(jié)構(gòu)就是如此,給定一個對象,返回一個響應(yīng)式對象。
其中 isObject 方法用于判斷是否是對象,不是對象不需要代理,直接返回即可。
reactive 方法的重點是 Proxy 的第二個參數(shù) handler ,它承載監(jiān)控對象變化,依賴收集,視圖更新等各項重大責(zé)任,我們重點來研究這個對象。
handler.js
在 Vue3 中 Proxy 的 handler 主要設(shè)置了 get , set , deleteProperty , has , ownKeys 這些屬性,即攔截了對象的讀取,設(shè)置,刪除, in 以及 Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法。
這里我們偷個懶,暫時就考慮 set 和 get 操作。
handler.get()
get 獲取屬性比較簡單,我們先來看看這個,這里我們用一個方法創(chuàng)建 getHanlder 。
這里推薦使用了 Reflect.get 而并非 target[key] 。
可以發(fā)現(xiàn), Vue3 是在取值的時候才去遞歸遍歷屬性的,而非 Vue2 中一開始就遞歸 data 給每個屬性添加 Watcher ,這也是 Vue3 性能提升之一。
handler.set()
同理 set 操作,我們也是用一個方法創(chuàng)建 setHandler 。
Reflect.set 會返回一個 Boolean 值,用于判斷屬性是否設(shè)置成功。
完事后將 handler 導(dǎo)出,然后在 reactive 中引入即可。
測試幾組對象貌似沒啥問題,其實是有一個坑,這個坑也跟數(shù)組有關(guān)。
如上例子,如果我們選擇代理數(shù)組,在 setHandler 中打印其 key 和 value 的話會得到 3 4 , length 4 這兩組值:
如果不作處理,那么會導(dǎo)致如果更新視圖的話,則會觸發(fā)兩次,這肯定是不允許的,因此,我們需要將區(qū)分新增和修改這兩種操作。
Vue3 中是通過判斷 target 是否存在該屬性來區(qū)分是新增還是修改操作,需要借助一個工具方法 —— hasOwnProperty 。
這里我們將上述的 createSetter 方法修改如下:
如此一來,我們調(diào) push 方法的時候,就只會觸發(fā)一次更新了,非常巧妙的避免了無意義的更新操作。
effect.js
光上述構(gòu)造響應(yīng)式對象并不能完成響應(yīng)式的操作,我們還需要一個非常重要的方法 effect ,它會在初始化執(zhí)行的時候存儲跟其有關(guān)的數(shù)據(jù)依賴,當(dāng)依賴數(shù)據(jù)發(fā)生變化的時候,則會再次觸發(fā) effect 傳遞的函數(shù)。
其基本雛形如下,入?yún)⑹且粋€函數(shù),還有個可選參數(shù) options 方便后面計算屬性等使用,暫時不考慮:
createReactiveEffect 就是為了將 fn 變成響應(yīng)式函數(shù),監(jiān)控數(shù)據(jù)變化,執(zhí)行 fn 函數(shù),因此該函數(shù)是一個高階函數(shù)。
createReactiveEffect 將原來的 fn 轉(zhuǎn)變成一個 reactvieEffect , 并將當(dāng)前的 effect 掛到全局的 activeEffect 上,目的是為了一會與當(dāng)前所依賴的屬性做好對應(yīng)關(guān)系。
我們必須要將依賴屬性構(gòu)造成 { prop : [effect,effect] } 這種結(jié)構(gòu),才能保證依賴屬性變化的時候,依次去觸發(fā)與之相關(guān)的 effect ,因此,需要在 get 屬性的時候,做屬性的依賴收集,將屬性與 effect 關(guān)聯(lián)起來。
依賴收集 —— track
在獲取對象的屬性時,會觸發(fā) getHandler ,再次做屬性的依賴收集,即 Vue2 中的發(fā)布訂閱。
在 setHandler 中獲取屬性的時候,做一次 track(target, key) 操作。
整個 track 的數(shù)據(jù)結(jié)構(gòu)大概是這樣
目的就是將 target , key , effect 之間做好對應(yīng)的關(guān)系映射。
打印 targetMap 的結(jié)構(gòu)如下:
**觸發(fā)更新 —— trigger **
上述已經(jīng)完成了依賴收集,剩下就是監(jiān)控數(shù)據(jù)變化,觸發(fā)更新操作,即在 setHandler 中添加 trigger 觸發(fā)操作。
這樣一來,獲取數(shù)據(jù)的時候通過 track 進(jìn)行依賴收集,更新數(shù)據(jù)的時候再通過 trigger 進(jìn)行更新,就完成了整個數(shù)據(jù)的響應(yīng)式操作。
再回頭看看我們先前提到的例子:
控制臺會依次打印 Hello ***** effect ***** 以及 World ***** effect ***** , 分別是首次渲染觸發(fā)跟更新數(shù)據(jù)重渲染觸發(fā),至此功能實現(xiàn)!
整體來說, Vue3 相比于 Vue2 在很多方面都做了調(diào)整,數(shù)據(jù)的響應(yīng)式只是冰山一角,但是可以看出尤大團(tuán)隊非常巧妙的利用了 Proxy 的特點以及 es6 的數(shù)據(jù)結(jié)構(gòu)和方法。另外, Composition API 的模式跟 React 在某些程度上有異曲同工之妙,這種設(shè)計模式讓我們在實際開發(fā)使用中更加的方法快捷,值得我們?nèi)W(xué)習(xí),加油!
最后附上倉庫地址 github ,歡迎各位大佬批評斧正~
vue響應(yīng)式原理是什么?
vue響應(yīng)式基本原理是基于Object.defineProperty(obj,prop,descriptor),descriptor里面可以定義get和set方法,可以在獲取屬性值事觸發(fā)get方法(可以收集依賴),設(shè)置屬性值時觸發(fā)set方法(更新依賴)。Vue最獨特的特性之一,是其非侵入性的響應(yīng)式系統(tǒng)。數(shù)據(jù)模型僅僅是普通的JavaScript對象。而當(dāng)你修改它們時,視圖會進(jìn)行更新。
vue響應(yīng)式系統(tǒng)
vue作為一個前端框架,近兩年非常的火,雖然它的社區(qū)不像react那樣繁榮,但它配套的東西都有固定的團(tuán)隊維護(hù),用起來更方便。它是MVVM模型的框架(不熟悉框架模型的同學(xué)可以看看阮一峰大神的博客,或者點這里),實現(xiàn)數(shù)據(jù)的雙向綁定,與其他框架相比vue非常的輕量級,另一個重要的特點就是它的響應(yīng)式系統(tǒng)。
vue2響應(yīng)式原理總結(jié)
vue組件實例化時,會對data屬性深度遍歷(遇到數(shù)組或者對象)為每一個屬性添加數(shù)據(jù)劫持。數(shù)據(jù)劫持就是使用Object.defineProperty(de fai in pro pu tei)方法添加get/set方法。
在這個過程中會實例化一個Dep類。
1.在get攔截器里觸發(fā)dep實例的depend方法,進(jìn)行依賴收集,實質(zhì)是在dep的實例屬性sub數(shù)組中添加依賴這個屬性的watcher實例。
2.在set攔截器里觸發(fā)dep實例的notify方法,對收集到的所有依賴派發(fā)更新,(watcher的update方法)
vue組件實例化時會實例化一個渲染watcher,渲染watcher實例化過程會做兩件事情。
1.創(chuàng)建vnode,在這個過程中,訪問了data屬性,觸發(fā)了get方法,完成了依賴收集。
2.觸發(fā)了子組件的實例化,子組件實例化又會重復(fù)上述數(shù)據(jù)劫持的過程。
這個過程就是對組件樹的深度遍歷。
結(jié)合組件生命周期來看整個過程,父組件會先觸發(fā)created鉤子,子組件后觸發(fā)created鉤子。而子組件mouted鉤子會先執(zhí)行,父組件的mouted鉤子后執(zhí)行。
分步驟記憶
1、實現(xiàn)頁面不刷新的原理
2、頁面視圖刷新的原理
實現(xiàn)頁面不刷新
1.hash
2.history
3.abstract:支持所有 JavaScript 運行環(huán)境,如 Node.js 服務(wù)器端。如果發(fā)現(xiàn)沒有瀏覽器的 API,路由會自動強(qiáng)制進(jìn)入這個模式。
1.hash(哈希模式),#符號后邊是瀏覽器行為,在改變的時候不對頁面進(jìn)行刷新(重新請求URL)(監(jiān)聽hashChange事件)
2.history模式,H5新增了pushState,replaceState連個新API,可以修改歷史記錄卻不會使瀏覽器刷新頁面。
視圖更新原理
其原理就是vue的響應(yīng)式更新dom的原理,m = v
m是數(shù)據(jù),也就是在vue-router install時在根組件(root vue component)添加了_route屬性,在匹配到對應(yīng)路由后更新了_route屬性值,繼而觸發(fā)了該屬性值的渲染watcher,在繼而觸發(fā)dom更新。
兩種模式的不同
1.部署時,history模式需要服務(wù)端處理所有可能的路徑(例如配置nginx的配置文件),防止出現(xiàn)404。哈希模式則不需要。
2.URL表示不同。
v-model指令就是 v-bind:value 和 @input 的語法糖。
它即可以支持原生表單元素,也可以支持自定義組件
在自定義組件中其實際是這樣的:
它的實現(xiàn)通過自定義render函數(shù), 緩存了 vnode
Vue 在更新 DOM 時是異步執(zhí)行的,只要偵聽到數(shù)據(jù)變化,Vue 將開啟一個隊列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更。
如果同一個 watcher 被多次觸發(fā),只會被推入到隊列中一次。在緩沖時會去除重復(fù)數(shù)據(jù)避免不必要的計算和 DOM 操作。
$nextTick(cb) 目的是在DOM 更新完成后傳入的回調(diào)函數(shù)再被調(diào)用。
vue2vue3響應(yīng)式原理的介紹就聊到這里吧,感謝你花時間閱讀本站內(nèi)容,更多關(guān)于vue的響應(yīng)原理、vue2vue3響應(yīng)式原理的信息別忘了在本站進(jìn)行查找喔。
掃描二維碼推送至手機(jī)訪問。
版權(quán)聲明:本文由飛速云SEO網(wǎng)絡(luò)優(yōu)化推廣發(fā)布,如需轉(zhuǎn)載請注明出處。