Hello,各位小伙伴,接下來的一段時間里,我會把我的課程《Vue.js 3.0 核心源碼解析》中問題的答案陸續在我的公眾號發布,由于課程的問題大多數都是開放性的問題,所以我的答案也不一定是標準的,僅供你參考喔。
本期的問題:為什么說 Vue.js 3 的響應式 API 實現和 Vue.js 2.x 相比性能要好,具體好在哪里呢?它又有哪些不足呢?
響應式實現方式
響應式原理是 Vue.js 的核心思想之一,它的本質是當數據變化后會自動執行某個函數。
響應式的實現基本都是靠數據劫持,在 Vue.js 2.x 中,是通過 Object.defineProperty
API 劫持數據的變化,在數據被訪問的時候收集依賴,然后在數據被修改的時候通知依賴更新。
而到了 Vue.js 3.0,作者使用 Proxy
API 來劫持數據,并重寫了響應式部分。
Proxy VS Object.defineProperty
那么,Proxy
和 Object.defineProperty
有哪些區別呢?
從 API 上來看,Proxy
劫持的是整個對象,那么對于對象屬性的新增、刪除、修改自然都可以劫持到;而Object.defineProperty
API 劫持的對象某一個屬性的訪問和修改,因此它不能監聽對象屬性新增和刪除。
從兼容性上來看,Object.defineProperty
支持所有主流瀏覽器,并兼容 IE9+,而 Proxy
支持現代主流瀏覽器,但唯獨不支持 IE,在國內 PC 端還沒有完全放棄 IE 的大環境下,導致 Vue.js 3.0 的普及受到限制。
從性能上看,Proxy
比 Object.defineProperty
要慢。沒錯,是慢喔,為了測試它們的性能差異,我特地寫了一個測試 demo,放在了 GitHub 上 https://github.com/ustbhuangyi/Proxy-vs-DefineProperty,感興趣的同學可以 clone 下來跑一下。
性能差異
既然 Proxy
比 Object.defineProperty
慢,那么為何說 Vue.js 3.0 的響應式 API 實現和 Vue.js 2.x 相比性能要好呢?
其實這個性能好主要體現在初始化階段。Vue.js 2.x 內部把某個對象變成響應式的時候,如果遇到對象的某個屬性的值仍然是對象的時候,會遞歸把子對象也變成響應式。
到了 Vue.js 3.0,并不會在初始階段遞歸響應式,而是在對象屬性被訪問的時候才遞歸執行下一步 reactive
,這其實是一種延時定義子對象響應式的實現,在性能上會有較大的提升。
說到延時響應式,那么 Vue.js 2.x 也可以這么做嗎,其實也是可以的,我對 Vue.js 2.x 的響應式源碼部分做了修改,如下:
??Object.defineProperty(obj,?key,?{enumerable:?true,configurable:?true,get:?function?reactiveGetter()?{const?value?=?getter???getter.call(obj)?:?vallet?childOb?=?!shallow?&&?observe(value)if?(Dep.target)?{dep.depend()if?(childOb)?{childOb.dep.depend()if?(Array.isArray(value))?{dependArray(value)}}}return?value}//?...})
改動很簡單,就是把遞歸的 observe
放在了 getter
中執行。
改完后我跑了一下?Vue.js 的單元測試,發現只有幾個測試沒通過,但沒通過的測試用例是因為我們改動的邏輯影響了這些測試用例原本的含義,但實際上并無本質的影響,因此在 Vue.js 2.x 中,把遞歸響應式的邏輯放在 getter
中也是可行的。
到這里你可能會問,如果延時響應式,那會不會每次訪問數據的時候都要重新定義一次響應式呢,其實是不用的,在 Vue.js 2.x 中,在執行一次 observe
后,會把觀察者對象 ob
保留在 value.__ob__
屬性中;而在 Vue.js 3.0 中,會用 reactiveMap
保留已定義的響應式對象,這樣下一次就直接從緩存里拿到對應的值了,這就是典型的空間換時間的思想。
總結
所以就響應式的實現而言,Vue.js 3.0 比 Vue.js 2.x 在性能上的優勢主要體現在初始化階段,不需要遞歸把子對象定義成響應式。而 Proxy
本身并不比 Object.defineProperty
快,好處是在于可以直接對整個對象劫持,包括對象屬性的新增和刪除,劣勢就是瀏覽器的兼容性不夠好,而且沒有合適的 polyfill。
我出這個題主要是希望你能做到以下兩點:
從源碼層面探索,了解 Vue.js 響應式的實現原理。
對比 Vue.js 2.x 和 Vue.js 3.0 在響應式實現上的差異。
要記住,分析和思考的過程遠比答案重要。
最近組建了一個江西人的前端交流群,如果你也是江西人可以加我微信ruochuan12 拉你進群。
你好,我是若川,江西人~(點擊藍字了解我)歷時一年只寫了一個學習源碼整體架構系列?有哪些必看的JS庫:jQuery、underscore、lodash、sentry、vuex、axios、koa、redux
關注
若川視野
,回復"pdf" 領取優質前端書籍pdf,回復"1",可加群長期交流學習我的博客地址:https://lxchuan12.gitee.io?歡迎收藏
覺得文章不錯,可以?分享、點贊、在看?呀^_^另外歡迎
留言
交流~
小提醒:若川視野公眾號面試、源碼等文章合集在菜單欄中間
【源碼精選】
按鈕,歡迎點擊閱讀,也可以星標我的公眾號,便于查找