mpvue原理分析


為什么要做小程序框架?

  1. 組件機制
  2. 多端復用
 
小程序實現原理
 
數據驅動視圖更新;視圖交互觸發事件,事件響應函數修改數據再次觸發視圖更新
 
 
mpvue原理
 
jsBridge
vue.js和小程序的工作原理一致,可以把小程序的功能托管給vue.js,在正確的時機將數據變更同步到小程序,從而達到開發小程序的目的。這樣,我們可以將精力聚焦在 Vue.js 上,參照 Vue.js 編寫與之對應的小程序代碼,小程序負責視圖層展示,所有業務邏輯收斂到 Vue.js 中,Vue.js 數據變更后同步到小程序,如圖2所示。如此一來,我們就獲得了以 Vue.js 的方式開發小程序的能力
 
 
生命周期關聯:
vue和小程序的數據彼此隔離,各有不同的更新機制。mpvue從生命周期和事件回調函數切入,在vue觸發數據更新時實現數據同步。小程序通過視圖層呈現給用戶、通過事件響應用戶交互,vue在后台維護這數據的變更和邏輯。為了實現數據的同步,mpvue修改了vue的runtime實現,在vue的生命周期中增加了更新小程序數據的邏輯。
 
事件代理機制:
用戶交互觸發的數據更新通過事件的代理機制完成。vue中,事件響應函數對應組件的method,vue自動維護了上下文環境。然而在小程序中沒有這種機制,vue執行環境中維護了一份實時虛擬DOM,這與小程序視圖層完全對應,小程序組件上觸發事件后,只要找到虛擬DOM上對應的節點,觸發對應的事件就可以了;另一方面,vue事件響應如果觸發了數據更新,其生命周期函數更新將自動觸發,在此函數上同步更新數據。
 
 
事件代理機制源碼分析
 
對比小程序事件系統,mpvue事件系統和Dom事件系統
// 小程序 event 對象屬性(8 個)
 
["type", "timeStamp", "target", "currentTarget", "detail", "touches", "changedTouches", "_requireActive"]
 
// DOM event 對象屬性 / 方法(54 個)
 
["isTrusted", "screenX", "screenY", "clientX", "clientY", "ctrlKey", "shiftKey", "altKey", "metaKey", "button", "buttons", "relatedTarget", "pageX", "pageY", "x", "y", "offsetX", "offsetY", ..., "cancelable", "timeStamp", "srcElement", "returnValue", "cancelBubble", "path", "composedPath", "stopPropagation", "stopImmediatePropagation", "preventDefault", "initEvent"]
// mpvue event 對象屬性 / 方法(9 個)
 
["mp", "type", "timeStamp", "x", "y", "target", "currentTarget", "stopPropagation", "preventDefault"]
  1. 在mpvue生成的wxml中,所有事件都被hanleProxy的函數接管,在handleProxy進行處理后再去調用我們寫的真正的事件處理函數。這個方法在initMp時,作為小程序page的構造函數的一個選項,從而可以在wxml中被正確調用

  1. handleProxy將小程序的event對象傳給handleProxyWithVue函數進行進一步處理
  2. handleProxyWithVue的作用

    (1) 從跟實例開始,根據comkey找出事件處理函數所在的mpvue示例(getVm)

    (2) 通過遍歷找到的vm的vnode,結合eventid找到小程序事件對應的真是的事件處理函數(getHandle)

    (3) 將小程序的event對象包裝成mpvue的event對象(getWebEventByMP),並添加了preventDafault和stopPropagation方法,但是preventDafault和stopPropagation方法是兩個空函數(noop),所以組織冒泡還是得使用.stop修飾符通過compile編譯成catchEvent

  1. 將包裝后的event對象(getWebEventByMP), 傳給真實的處理函數進行調用
 
(生成的wxml中綁定事件的節點都有data-comkeydata-eventid屬性,在一個事件觸發時,它們是被用來尋找事件對應的vm實例和對應的事件處理函數的)
 
 
 
 
原有的mpvue更新機制:
mpvue實現原理是基於Vue2.js,重寫platform部分代碼來實現在小程序環境下用Vue組件系統進行運行。在Vue的H5實現中,當我們組件樹上的一個組件屬性更改后,會觸發整個樹的檢查更新,然后在新老dom樹對比算出最小改動后,同步到瀏覽器的真實dom,這個過程熟悉Vue的開發者很熟悉了,就是diff更新。
但是H5版的diff最后的瀏覽器runtime代碼是基於增刪dom節點API進行的,小程序又不提供增刪節點的功能,所以為了能在小程序環境實現更新,原版mpvue對整個觸發更新檢查的V-dom樹都取值轉換成了小程序對應的JSON,通過setData()接口同步到視圖。這個過程在實際運行會造成setData的數據冗余過大。通過代理updateDataToMP打日志的方式我們發現,v-dom樹上任意節點的任意屬性更改,會引發整棵樹的更新,一次形如this.a = 1的操作會引起O(N^2)量級的更新。真實在項目中監控到,一個10個組件左右構成的頁面,每次進行一次this.a=1數據更新,在$nextTick渲染時真實傳到小程序的數據大概在10k-20k。安卓真機上會造成大概200-300ms的渲染演示,肉眼能較明顯覺察。
 
新mpvue數據更新機制:
新版Mpvue在每次數據更新的時候,會在Vue監聽set方法,每次觸發屬性更新的時候把當前更新的屬性key放在當前V-dom的__keyPath屬性中。一次更新全部觸發后,在實際render過程中遍歷keyPath屬性,只選擇更新的屬性放到json里,調用Page.setData來進行更新操作。同時在Vue.$nextTick函數里,觸發完所有的render更新后會清理掉全部keyPath,防止下次再更新又冗余。通過這種操作,this.a=1可以O(N^2)量級降低到O(1).上面例子中每次更新10k-20k的頁面,在業務中有比如用戶操作引起某個組件數字+1,關閉彈窗等操作時,更新量降低到幾個字節。安卓卡頓的問題也從框架角度完美解決


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM