乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      網(wǎng)上都說操作真實(shí) DOM 慢,但測(cè)試結(jié)果卻比 React 更快,為什么?

       3克拉的Anran 2022-05-02 發(fā)布于北京

      這里面有好幾個(gè)方面的問題。

      1. 原生 DOM 操作 vs. 通過框架封裝操作。

      這是一個(gè)性能 vs. 可維護(hù)性的取舍??蚣艿囊饬x在于為你掩蓋底層的 DOM 操作,讓你用更聲明式的方式來(lái)描述你的目的,從而讓你的代碼更容易維護(hù)。沒有任何框架可以比純手動(dòng)的優(yōu)化 DOM 操作更快,因?yàn)榭蚣艿?DOM 操作層需要應(yīng)對(duì)任何上層 API 可能產(chǎn)生的操作,它的實(shí)現(xiàn)必須是普適的。針對(duì)任何一個(gè) benchmark,我都可以寫出比任何框架更快的手動(dòng)優(yōu)化,但是那有什么意義呢?在構(gòu)建一個(gè)實(shí)際應(yīng)用的時(shí)候,你難道為每一個(gè)地方都去做手動(dòng)優(yōu)化嗎?出于可維護(hù)性的考慮,這顯然不可能??蚣芙o你的保證是,你在不需要手動(dòng)優(yōu)化的情況下,我依然可以給你提供過得去的性能。

      2. 對(duì) React 的 Virtual DOM 的誤解。

      React 從來(lái)沒有說過 “React 比原生操作 DOM 快”。React 的基本思維模式是每次有變動(dòng)就整個(gè)重新渲染整個(gè)應(yīng)用。如果沒有 Virtual DOM,簡(jiǎn)單來(lái)想就是直接重置 innerHTML。很多人都沒有意識(shí)到,在一個(gè)大型列表所有數(shù)據(jù)都變了的情況下,重置 innerHTML 其實(shí)是一個(gè)還算合理的操作... 真正的問題是在 “全部重新渲染” 的思維模式下,即使只有一行數(shù)據(jù)變了,它也需要重置整個(gè) innerHTML,這時(shí)候顯然就有大量的浪費(fèi)。

      我們可以比較一下 innerHTML vs. Virtual DOM 的重繪性能消耗:

      innerHTML: render html string O(template size) + 重新創(chuàng)建所有 DOM 元素 O(DOM size)

      Virtual DOM: render Virtual DOM + diff O(template size) + 必要的 DOM 更新 O(DOM change)

      Virtual DOM render + diff 顯然比渲染 html 字符串要慢,但是!它依然是純 js 層面的計(jì)算,比起后面的 DOM 操作來(lái)說,依然便宜了太多。可以看到,innerHTML 的總計(jì)算量不管是 js 計(jì)算還是 DOM 操作都是和整個(gè)界面的大小相關(guān),但 Virtual DOM 的計(jì)算量里面,只有 js 計(jì)算和界面大小相關(guān),DOM 操作是和數(shù)據(jù)的變動(dòng)量相關(guān)的。前面說了,和 DOM 操作比起來(lái),js 計(jì)算是極其便宜的。這才是為什么要有 Virtual DOM:它保證了 1)不管你的數(shù)據(jù)變化多少,每次重繪的性能都可以接受;2) 你依然可以用類似 innerHTML 的思路去寫你的應(yīng)用。

      3. MVVM vs. Virtual DOM

      相比起 React,其他 MVVM 系框架比如 Angular, Knockout 以及 Vue、Avalon 采用的都是數(shù)據(jù)綁定:通過 Directive/Binding 對(duì)象,觀察數(shù)據(jù)變化并保留對(duì)實(shí)際 DOM 元素的引用,當(dāng)有數(shù)據(jù)變化時(shí)進(jìn)行對(duì)應(yīng)的操作。MVVM 的變化檢查是數(shù)據(jù)層面的,而 React 的檢查是 DOM 結(jié)構(gòu)層面的。MVVM 的性能也根據(jù)變動(dòng)檢測(cè)的實(shí)現(xiàn)原理有所不同:Angular 的臟檢查使得任何變動(dòng)都有固定的 O(watcher count) 的代價(jià);Knockout/Vue/Avalon 都采用了依賴收集,在 js 和 DOM 層面都是 O(change):

      臟檢查:scope digest O(watcher count) + 必要 DOM 更新 O(DOM change)

      依賴收集:重新收集依賴 O(data change) + 必要 DOM 更新 O(DOM change)

      可以看到,Angular 最不效率的地方在于任何小變動(dòng)都有的和 watcher 數(shù)量相關(guān)的性能代價(jià)。但是!當(dāng)所有數(shù)據(jù)都變了的時(shí)候,Angular 其實(shí)并不吃虧。依賴收集在初始化和數(shù)據(jù)變化的時(shí)候都需要重新收集依賴,這個(gè)代價(jià)在小量更新的時(shí)候幾乎可以忽略,但在數(shù)據(jù)量龐大的時(shí)候也會(huì)產(chǎn)生一定的消耗。

      MVVM 渲染列表的時(shí)候,由于每一行都有自己的數(shù)據(jù)作用域,所以通常都是每一行有一個(gè)對(duì)應(yīng)的 ViewModel 實(shí)例,或者是一個(gè)稍微輕量一些的利用原型繼承的 "scope" 對(duì)象,但也有一定的代價(jià)。所以,MVVM 列表渲染的初始化幾乎一定比 React 慢,因?yàn)閯?chuàng)建 ViewModel / scope 實(shí)例比起 Virtual DOM 來(lái)說要昂貴很多。這里所有 MVVM 實(shí)現(xiàn)的一個(gè)共同問題就是在列表渲染的數(shù)據(jù)源變動(dòng)時(shí),尤其是當(dāng)數(shù)據(jù)是全新的對(duì)象時(shí),如何有效地復(fù)用已經(jīng)創(chuàng)建的 ViewModel 實(shí)例和 DOM 元素。假如沒有任何復(fù)用方面的優(yōu)化,由于數(shù)據(jù)是 “全新” 的,MVVM 實(shí)際上需要銷毀之前的所有實(shí)例,重新創(chuàng)建所有實(shí)例,最后再進(jìn)行一次渲染!這就是為什么題目里鏈接的 angular/knockout 實(shí)現(xiàn)都相對(duì)比較慢。相比之下,React 的變動(dòng)檢查由于是 DOM 結(jié)構(gòu)層面的,即使是全新的數(shù)據(jù),只要最后渲染結(jié)果沒變,那么就不需要做無(wú)用功。

      Angular 和 Vue 都提供了列表重繪的優(yōu)化機(jī)制,也就是 “提示” 框架如何有效地復(fù)用實(shí)例和 DOM 元素。比如數(shù)據(jù)庫(kù)里的同一個(gè)對(duì)象,在兩次前端 API 調(diào)用里面會(huì)成為不同的對(duì)象,但是它們依然有一樣的 uid。這時(shí)候你就可以提示 track by uid 來(lái)讓 Angular 知道,這兩個(gè)對(duì)象其實(shí)是同一份數(shù)據(jù)。那么原來(lái)這份數(shù)據(jù)對(duì)應(yīng)的實(shí)例和 DOM 元素都可以復(fù)用,只需要更新變動(dòng)了的部分。或者,你也可以直接 track by $index 來(lái)進(jìn)行 “原地復(fù)用”:直接根據(jù)在數(shù)組里的位置進(jìn)行復(fù)用。在題目給出的例子里,如果 angular 實(shí)現(xiàn)加上 track by $index 的話,后續(xù)重繪是不會(huì)比 React 慢多少的。甚至在 dbmonster 測(cè)試中,Angular 和 Vue 用了 track by $index 以后都比 React 快:

      dbmon

      (注意 Angular 默認(rèn)版本無(wú)優(yōu)化,優(yōu)化過的在下面)

      順道說一句,React 渲染列表的時(shí)候也需要提供 key 這個(gè)特殊 prop,本質(zhì)上和 track-by 是一回事。

      4. 性能比較也要看場(chǎng)合

      在比較性能的時(shí)候,要分清楚初始渲染、小量數(shù)據(jù)更新、大量數(shù)據(jù)更新這些不同的場(chǎng)合。Virtual DOM、臟檢查 MVVM、數(shù)據(jù)收集 MVVM 在不同場(chǎng)合各有不同的表現(xiàn)和不同的優(yōu)化需求。Virtual DOM 為了提升小量數(shù)據(jù)更新時(shí)的性能,也需要針對(duì)性的優(yōu)化,比如 shouldComponentUpdate 或是 immutable data。

      初始渲染:Virtual DOM > 臟檢查 >= 依賴收集

      小量數(shù)據(jù)更新:依賴收集 >> Virtual DOM + 優(yōu)化 > 臟檢查(無(wú)法優(yōu)化) > Virtual DOM 無(wú)優(yōu)化

      大量數(shù)據(jù)更新:臟檢查 + 優(yōu)化 >= 依賴收集 + 優(yōu)化 > Virtual DOM(無(wú)法/無(wú)需優(yōu)化)>> MVVM 無(wú)優(yōu)化

      不要天真地以為 Virtual DOM 就是快,diff 不是免費(fèi)的,batching 么 MVVM 也能做,而且最終 patch 的時(shí)候還不是要用原生 API。在我看來(lái) Virtual DOM 真正的價(jià)值從來(lái)都不是性能,而是它 1) 為函數(shù)式的 UI 編程方式打開了大門;2) 可以渲染到 DOM 以外的 backend,比如 ReactNative。

      5. 總結(jié)

      以上這些比較,更多的是對(duì)于框架開發(fā)研究者提供一些參考。主流的框架 + 合理的優(yōu)化,足以應(yīng)對(duì)絕大部分應(yīng)用的性能需求。如果是對(duì)性能有極致需求的特殊情況,其實(shí)應(yīng)該犧牲一些可維護(hù)性采取手動(dòng)優(yōu)化:比如 Atom 編輯器在文件渲染的實(shí)現(xiàn)上放棄了 React 而采用了自己實(shí)現(xiàn)的 tile-based rendering;又比如在移動(dòng)端需要 DOM-pooling 的虛擬滾動(dòng),不需要考慮順序變化,可以繞過框架的內(nèi)置實(shí)現(xiàn)自己搞一個(gè)。

        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多