H5大咖分享:Vue3為何使用Proxy實現數據監聽

2021-01-07 雲和數據

前言

vue3響應式數據放棄了Object.define Property,而使用Proxy來代替它。我們知道,在 vue2 中,實現數據監聽是使用Object.defineProperty --> 實現方法可看:vue 數據雙向綁定原理。

而這個方法有缺點,並且不能實現數組和對象的部分監聽情況;具體也可以看我之前寫的一篇博客:關於 Vue 不能 watch 數組 和 對象變化的解決方案。

最新的 Proxy,相比 vue2 的 Object.define Property,能達到速度加倍、內存減半的成效。具體是怎麼實現、以及對比舊的實現方法為啥能有速度加倍、內存減半的特性。

Vue 初始化過程

Vue 的初始化過程,分別有、和Observer、Compiler和Watcher。

當我們 new Vue 的時候,會調用Observer,通過 Object.defineProperty 遍歷 vue 對象的 data、computed 或者 props(如果是組件的話)的所有屬性進行監聽。同時通過Compiler解析模板指令,解析到屬性後就 new 一個Watcher並綁定更新函數到 watcher 當中,Observer 和 Compiler 就通過屬性來進行關聯。

如上,當 Observer 中的 setter 檢測到屬性值改變的時候,就調用屬性對應的所有 watcher 調用更新函數,從而更新到屬性對應的 dom。

Object.defineProperty

來個簡單的 Object.defineProperty 例子

輸出如下:

從上面可以知道:

Object.defineProperty 需要遍歷所有的屬性,這就造成了如果 vue 對象的 data/computed/props 中的數據規模龐大,那麼遍歷起來就會慢很多同理,如果 vue 對象的 data/computed/props 中的數據規模龐大,那麼 Object.defineProperty 需要監聽所有的屬性的變化,那麼佔用內存就會很大Proxy

再來看看 Proxy

Proxy 對象用於定義基本操作的自定義行為(如屬性查找,賦值,枚舉,函數調用等)

可以理解為在對象之前設置一個「攔截」,當監聽的對象被訪問的時候,都必須經過這層攔截。可以在這攔截中對原對象處理,返回需要的數據格式。

也就是無論訪問對象的什麼屬性,之前定義的或是新增的屬性,都會走到攔截中進行處理。這就解決了之前所無法監聽的問題。

官方例子:

const p = new Proxy(target, handler)

參數

target:要使用 Proxy 包裝的目標對象(可以是任何類型的對象,包括原生數組,函數,甚至另一個代理)handler:一個通常以函數作為屬性的對象,各屬性中的函數分別定義了在執行各種操作時代理 p 的行為來個實際 Proxy 例子

輸出如下:

設置的屬性為:age新的屬性:age 值為:22查看的屬性為:age22---設置的屬性為:single新的屬性:single 值為:NO查看的屬性為:singleNO---查看的屬性為:others查看的屬性為:othersboost

由上可知,新增或編輯屬性,並不需要重新添加響應式處理,都能監聽的到。因為 Proxy 是對對象的操作,只要你訪問對象,就會走到 Proxy 的邏輯中。

Reflect 是一個內置的對象,它提供攔截 JavaScript 操作的方法。這些方法與proxy handlers的方法相同。Reflect不是一個函數對象,因此它是不可構造的

區別

Proxy 和 Object.defineProperty 的使用方法看似很相似,其實 Proxy 是在更高維度上攔截屬性的。

Object.defineProperty

Vue2 中,對於給定的 data:如 { count: 1 },是需要根據具體的 key 也就是 count,去對 get 和 set 進行攔截,也就是:

Object.defineProperty(data, 'count', {get() {}, set() {},})

必須預先知道要攔截的 key 是什麼,這也就是為什麼 Vue2 裡對於對象上的新增屬性無能為力,所以 Vue 初始化的過程中需要遍歷 data 來挾持數據變化,造成速度變慢,內存變大的原因。

Proxy

而 Vue3 所使用的 Proxy,則是這樣攔截的:

new Proxy(data, {get(key) { }, set(key, value) { },})

可以看到,proxy 不需要關心具體的 key,它去攔截的是 修改 data 上的任意 key 和 讀取 data 上的任意 key。

所以,不管是已有的 key 還是新增的 key,都會監聽到。但是 Proxy 更加強大的地方還在於 Proxy 除了 get 和 set,還可以攔截更多的操作符,具體可看 MDN。

兼容性

Proxy 對 IE 不友好,vue3 在檢測到使用 IE 的情況下(包括 IE11),會自動降級為 Object.defineProperty 的數據監聽系統。

文/雲和數據H5高級工程師,H5前端開發培訓就來雲和數據!

相關焦點

  • 前端:Vue3為何使用Proxy實現數據監聽
    ,那麼遍歷起來就會慢很多.同理,如果 vue 對象的 data/computed/props 中的數據規模龐大,那麼 Object.defineProperty 需要監聽所有的屬性的變化,那麼佔用內存就會很大.
  • Vue2和Vue3使用層面上有什麼區別
    $emit(vue3中只能在methods裡使用)作用相同 context.emit用法 5. 5.1 使用場景 在vue2中我們在父組件綁定click事件,子組件必須內部觸發click,而vue3中在父組件綁定子組件的根元素上也會跟著綁定 ButtonDemo.vue Button.vue
  • Proxy使用詳解
    new操作執行完畢之後的數據結構巧妙利用原型鏈和代理handler形參中的receiverreceiver是代理或繼承代理的對象。通俗來講,就是觸發了handler的源頭對象。一般receiver即是target的代理實例。
  • 《前端會客廳》對話winter和尤雨溪,深度探尋Vue3設計思想(上)
    熱加載 基本都是100ms以內 相比於大項目webpack2S左右的體驗,差距是很大的。尤大願意往vite這類工具上投入精力,是個非常好的事情,大家苦webpack久矣。vite還給我一個啟發,就是尤大起名的藝術,vue和vite都是法語。
  • Proxy-Go v5.0 發布:DNS 汙染?不存在的!
    智能HTTP,SOCKS5代理,會自動判斷訪問的網站是否屏蔽,如果被屏蔽那麼就會使用上級代理(前提是配置了上級代理)訪問網站;如果訪問的網站沒有被屏蔽,為了加速訪問,代理會直接訪問網站,不使用上級代理.域名黑白名單,更加自由的控制網站的訪問方式。
  • Proxy-Go v4.4 發布,內網穿透性能大幅度提升
    Proxy是golang實現的高性能http,https,websocket,tcp,udp,socks5代理伺服器,支持正向代理、反向代理、透明代理、內網穿透、TCP/UDP埠映射、SSH中轉,TLS加密傳輸,協議轉換。
  • 手寫 Vue3 數據雙向綁定 理解Proxy
    前言vue3的 Proxy 最近貌似各大網紅公眾號都有發,我也來蹭蹭熱度寫一篇吧!我們也可以結合vue2來看看vue3到底發生了些什麼變化,又解決了Vue2.x的哪些痛點。接下來我們一起看看~目錄結構Proxy是什麼?Proxy 翻譯過來就是代理的意思,何為代理呢?
  • Proxy-Go v8.2 發布,內網穿透P2P!
    智能HTTP,SOCKS5代理,會自動判斷訪問的網站是否屏蔽,如果被屏蔽那麼就會使用上級代理(前提是配置了上級代理)訪問網站;如果訪問的網站沒有被屏蔽,為了加速訪問,代理會直接訪問網站,不使用上級代理。 域名黑白名單,更加自由的控制網站的訪問方式。
  • 【第1485期】初探 Vue3.0 中的一大亮點——Proxy !
    今日早讀文章由@Chris威分享。正文從這開始~~不久前,也就是11月14日-16日於多倫多舉辦的 VueConf TO 2018 大會上,尤雨溪發表了名為 Vue3.0 Updates 的主題演講,對 Vue3.0 的更新計劃、方向進行了詳細闡述(感興趣的小夥伴可以看看完整的 PPT),表示已經放棄使用了 Object.defineProperty,而選擇了使用更快的原生 Proxy !!
  • 中間件mysql-proxy的一些細節
    mysql-proxy是官方提供的mysql中間件產品可以實現負載平衡,讀寫分離,failover等,但其不支持大數據量的分庫分表且性能較差。Atlas(是由 Qihoo 360, Web平臺部基礎架構團隊開發維護的一個基於MySQL協議的數據中間層項目。)今天推薦一篇文章,深度分享mysql-proxy的細節。
  • 你不知道的 Proxy
    在 從觀察者模式到響應式的設計原理 這篇文章中,阿寶哥介紹了 observer-util 這個庫如何使用 Proxy 來實現響應式。而對於 vue-next 項目中的 @vue/reactivity 模塊,也是利用 Proxy 來實現響應式。因此,如果你要學習 @vue/reactivity 模塊的話,就需要先掌握 Proxy。
  • 菜鳥搭建 Mock 伺服器實踐:Anyproxy+Moco
    1、Anproxy:http://anyproxy.io/cn/AnyProxy 是一個基於 Node.js 的代理伺服器。只要代理伺服器可以實現靈活配置,前端工程師們的奇葩需求就有出頭之日了。特點:尤其是第3點,由於可以控制代理,所以就可以控制請求和響應的數據,其實就Anproxy本身就可以mock了,但存在一個問題,每次修改Mock數據之後都必須重啟Anproxy,一旦重啟Anyproxy,連接的客戶端就會斷開一次網絡,這樣對於即時通訊需要保持頻繁心跳的產品來說是一個比較致命的打擊,所以既不能重啟Anproxy,又想隨時改變Mock數據,那怎麼做了,這裡就可以用
  • 使用CLI開發一個Vue3的npm庫
    前言前幾天寫了一個Vue的自定義右鍵菜單的npm庫,主要講了插件的設計思路以及具體的實現過程,插件的開發流程沒有細講。本文就跟大家分享下如何使用CLI從零開始開發一個支持Vue3的庫,並上傳至npm,歡迎各位感興趣的開發者閱讀本文。
  • 更省錢地完成數據監聽
    觀察者模式的思路很簡單,它被廣泛地應用在各種數據監控上。很多時候我們希望監聽某個數據的變化,希望一旦獲悉它的變化之後便能立即採取一些舉措。按照常規的操作,我們需要開啟額外的線程來進行監聽。但開啟線程並不是最好的選擇,一是因為非常麻煩,二是會帶來額外的開銷。
  • Vue面試題(2)雙向數據綁定,MVVM
    ,整合observer、compile和watcher三者,通過observer來監聽自己的model數據變化,通過compile來編譯模板指令,最終利用watcher搭起的observer和compile之間的通信橋梁,達到數據變化---試圖更新;視圖交互變化(input)-->數據model變更的雙向綁定效果版本比較:vue是基於依賴收集的雙向綁定;3.0版本之前使用
  • 使用PixelLib來實現圖像分割
    圖像分割的一些主要應用包括:語義分割:使用相同類別的對象使用相同的顏色映射進行分割。實例分割:它不同於語義分割,它會對同一對象的不同實例用不同的顏色映射來進行分割。PixelLib:是為了在現實生活中更容易實現圖像分割而構建的庫。PixelLib是一個靈活的庫,可以集成到需要應用圖像分割的軟體解決方案中。
  • 使用Storm實現實時大數據分析!
    簡單和明了,Storm讓大數據分析變得輕鬆加愉快。當今世界,公司的日常運營經常會生成TB級別的數據。數據來源囊括了網際網路裝置可以捕獲的任何類型數據,網站、社交媒體、交易型商業數據以及其它商業環境中創建的數據。考慮到數據的生成量,實時處理成為了許多機構需要面對的首要挑戰。
  • 面試官:Vue3.0裡為什麼要用 Proxy API 替代 defineProperty API ?
    一、Object.defineProperty定義:Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,並返回此對象為什麼能實現響應式通過defineProperty 兩個屬性,get及set
  • 從一個需求說起,H5實現萬能返回
    當時覺得很簡單,調用window.onbeforeunload便可,很快實現了這個需求。於是去百度go(-1)的監聽事件popstate,然後在監聽回調裡讓自定義彈窗展示。思路是沒錯,可彈窗沒彈出來。於是在進入頁面前調localStorage加了個緩存,在監聽的回調裡把緩存清除,測試回調是否執行。是的,回調沒有執行,心裡一千個草泥馬在奔騰,一度懷疑這api是假的。於是把MDN文檔的例子複製過來,原來是思維打結了。