vue2vue3響應(yīng)式原理(vue的響應(yīng)原理)
今天給各位分享vue2vue3響應(yīng)式原理的知識,其中也會對vue的響應(yīng)原理進行解釋,如果能碰巧解決你現(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)有一段時間了,真可謂是千呼萬喚始出來??!
相比于 Vue2.x , Vue3.0 在新的版本中提供了更好的性能、更小的捆綁包體積、更好的 TypeScript 集成、用于處理大規(guī)模用例的新 API 。
在發(fā)布之前,尤大大就已經(jīng)聲明了響應(yīng)式方面將采用 Proxy 對于之前的 Object.defineProperty 進行改寫。其主要目的就是彌補 Object.defineProperty 自身的一些缺陷,例如無法檢測到對象屬性的新增或者刪除,不能監(jiān)聽數(shù)組的變化等。
而 Vue3 采用了新的 Proxy 實現(xiàn)數(shù)據(jù)讀取和設(shè)置攔截,不僅彌補了之前 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 方法是負責(zé)將數(shù)據(jù)變成響應(yīng)式, effect 方法的作用是根據(jù)數(shù)據(jù)變化去更新視圖或調(diào)用函數(shù),與 react 中的 useEffect 有點類似~
其大概用法如下:
默認會執(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 進行依賴收集,更新數(shù)據(jù)的時候再通過 trigger 進行更新,就完成了整個數(shù)據(jù)的響應(yīng)式操作。
再回頭看看我們先前提到的例子:
控制臺會依次打印 Hello ***** effect ***** 以及 World ***** effect ***** , 分別是首次渲染觸發(fā)跟更新數(shù)據(jù)重渲染觸發(fā),至此功能實現(xiàn)!
整體來說, Vue3 相比于 Vue2 在很多方面都做了調(diào)整,數(shù)據(jù)的響應(yīng)式只是冰山一角,但是可以看出尤大團隊非常巧妙的利用了 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)你修改它們時,視圖會進行更新。
vue響應(yīng)式系統(tǒng)
vue作為一個前端框架,近兩年非常的火,雖然它的社區(qū)不像react那樣繁榮,但它配套的東西都有固定的團隊維護,用起來更方便。它是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方法,進行依賴收集,實質(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,路由會自動強制進入這個模式。
1.hash(哈希模式),#符號后邊是瀏覽器行為,在改變的時候不對頁面進行刷新(重新請求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)式原理的信息別忘了在本站進行查找喔。
掃描二維碼推送至手機訪問。
版權(quán)聲明:本文由飛速云SEO網(wǎng)絡(luò)優(yōu)化推廣發(fā)布,如需轉(zhuǎn)載請注明出處。