在開發(fā)時,避免在同一流程內多次使用setData當然是最佳實踐。采取人工維護肯定是能夠實現的,就好比能用原生 js 能寫出比眾多框架更高效的性能一樣。但當頁面邏輯負責起來之后,花很大的精力去維護都不一定能保證每個流程只存在一次setData,而且可維護性也不高。因此,WePY選擇使用臟檢查去做數據綁定優(yōu)化。用戶不用再擔心在我的流程里,數據被修改了多少次,只會在流程最后做一次臟檢查,并且按需執(zhí)行setData。
臟檢測機制借鑒自AngularJS,多數人一聽到臟檢查都會覺得是低效率的一種作法,認為使用 Vue.js 中的 getter,setter更高效。其實不然,兩種機制都是對同一件事的不同實現方式。各有優(yōu)劣,取決于使用的人在使用過程中是否正好放大了機制中的劣勢面。
WePY 中的 setData 就好比是一個 setter,在每次調用時都會去渲染視圖。因此如果再封裝一層 getter、setter 就完全沒有意義,沒有任何優(yōu)化可言。這也就是為什么一個類 Vue.js 的小程序框架卻選擇了與之相反的另外一種數據綁定方式。
再回來看臟檢查的問題在哪里,從上面實驗的代碼可以看出,臟檢查的性能問題在于每次進行臟檢查時,需要遍歷所以數據并且作值的深比較,性能取決于遍歷以及比較數據的大小。WePY 中深比較是使用的 underscore 的 isEqual 方法。為了驗證效率問題,使用不同的比較方法對一個 16.7 KB 的復雜 JSON 數據進行深比較,測試用例請看這里:deep-compare-test-case
得到的結果如下:
圖片描述
從結果來看,對于一個 16.7 KB 的數據深比較是完全不足以產生性能問題的。那 AngularJS 1.x 臟檢查的性能問題是怎么出現的呢?
AngularJS 1.x 中沒有組件的概念,頁面數據就位于 controller 的 $scope 當中。每一次臟檢查都是從 $rootScope 開始,隨后遍歷至所有子 $scope。參考這里 angular.js:L1081。對于一個大型的單頁應用來說,所有 $scope 中的數據可能達到了上百甚至上千個都有可能。那時,臟檢查的每次遍歷就可能真的會成為了性能的瓶頸了。
反觀 WePY,使用類似于 Vue.js 的組件化開發(fā),在拋開父子組件雙向綁定通信的情況下,組件的臟檢查僅針對組件本身的數據進行,一個組件的數據通常不會太多,數據太多時可以細化組件劃分的粒度。因此在這種情況下,臟檢查并不會導致性能問題。
其實,在很多情況下,框架封裝的解決方案都不是性能優(yōu)化的最優(yōu)解決方案,使用原生肯定能優(yōu)化出更快的代碼。但它們之所以存在并且有價值,那都是因為它們是在性能、開發(fā)效率、可維護性上尋找到一個平衡點,這也是為什么 WePY 選擇使用臟檢查作為數據綁定的優(yōu)化。
更多建議: