欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談React的最大亮點(diǎn)之虛擬DOM

 更新時(shí)間:2024年07月01日 14:28:29   作者:TAT.  
這篇文章主要介紹了淺談React的最大亮點(diǎn)之虛擬DOM,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

在Web開(kāi)發(fā)中,需要將數(shù)據(jù)的變化實(shí)時(shí)反映到UI上,這時(shí)就需要對(duì)DOM進(jìn)行操作,但是復(fù)雜或頻繁的DOM操作通常是性能瓶頸產(chǎn)生的原因,為此,React引入了虛擬DOM(Virtual DOM)的機(jī)制。

一、什么是虛擬DOM?

在React中,render執(zhí)行的結(jié)果得到的并不是真正的DOM節(jié)點(diǎn),結(jié)果僅僅是輕量級(jí)的JavaScript對(duì)象,我們稱之為virtual DOM。

虛擬DOM是React的一大亮點(diǎn),具有batching(批處理)和高效的Diff算法。這讓我們可以無(wú)需擔(dān)心性能問(wèn)題而”毫無(wú)顧忌”的隨時(shí)“刷新”整個(gè)頁(yè)面,由虛擬 DOM來(lái)確保只對(duì)界面上真正變化的部分進(jìn)行實(shí)際的DOM操作。在實(shí)際開(kāi)發(fā)中基本無(wú)需關(guān)心虛擬DOM是如何運(yùn)作的,但是理解其運(yùn)行機(jī)制不僅有助于更好的理解React組件的生命周期,而且對(duì)于進(jìn)一步優(yōu)化 React程序也會(huì)有很大幫助。

二、虛擬DOM VS 直接操作原生DOM?

如果沒(méi)有 Virtual DOM,簡(jiǎn)單來(lái)說(shuō)就是直接重置 innerHTML。這樣操作,在一個(gè)大型列表所有數(shù)據(jù)都變了的情況下,還算是合理,但是,當(dāng)只有一行數(shù)據(jù)發(fā)生變化時(shí),它也需要重置整個(gè) innerHTML,這時(shí)候顯然就造成了大量浪費(fèi)。

比較innerHTML 和Virtual DOM 的重繪過(guò)程如下:

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

Virtual DOM: render Virtual DOM + diff + 必要的 DOM 更新

和 DOM 操作比起來(lái),js 計(jì)算是非常便宜的。Virtual DOM render + diff 顯然比渲染 html 字符串要慢,但是,它依然是純 js 層面的計(jì)算,比起后面的 DOM 操作來(lái)說(shuō),依然便宜了太多。當(dāng)然,曾有人做過(guò)驗(yàn)證說(shuō)React的性能不如直接操作真實(shí)DOM,代碼如下:

function Raw() {
  var data = _buildData(),
    html = "";
  ...
  for(var i=0; i<data.length; i++) {
    var render = template;
    render = render.replace("{{className}}", "");
    render = render.replace("{{label}}", data[i].label);
    html += render;
  }
  ...
  container.innerHTML = html;
  ...
}

該測(cè)試用例中雖然構(gòu)造了一個(gè)包含1000個(gè)Tag的String,并把它添加到DOM樹(shù)中,但是只做了一次DOM操作。然而,在實(shí)際開(kāi)發(fā)過(guò)程中,這1000個(gè)元素更新可能分布在20個(gè)邏輯塊中,每個(gè)邏輯塊中包含50個(gè)元素,當(dāng)頁(yè)面需要更新時(shí),都會(huì)引起DOM樹(shù)的更新,上述代碼就近似變成了如下格式:

function Raw() {
  var data = _buildData(), 
    html = ""; 
  ... 
  for(var i=0; i<data.length; i++) { 
    var render = template; 
    render = render.replace("{{className}}", ""); 
    render = render.replace("{{label}}", data[i].label); 
    html += render; 
    if(!(i % 50)) {
      container.innerHTML = html;
    }
  } 
  ... 
}

這樣來(lái)看,React的性能就遠(yuǎn)勝于原生DOM操作了。

而且,DOM 完全不屬于Javascript (也不在Javascript 引擎中存在).。Javascript 其實(shí)是一個(gè)非常獨(dú)立的引擎,DOM其實(shí)是瀏覽器引出的一組讓Javascript操作HTML文檔的API而已。在即時(shí)編譯的時(shí)代,調(diào)用DOM的開(kāi)銷是很大的。而Virtual DOM的執(zhí)行完全都在Javascript 引擎中,完全不會(huì)有這個(gè)開(kāi)銷。

React.js 相對(duì)于直接操作原生DOM有很大的性能優(yōu)勢(shì), 很大程度上都要?dú)w功于virtual DOM的batching 和diff。batching把所有的DOM操作搜集起來(lái),一次性提交給真實(shí)的DOM。diff算法時(shí)間復(fù)雜度也從標(biāo)準(zhǔn)的的Diff算法的O(n^3)降到了O(n)。這里留到下一次博客單獨(dú)講。

三、虛擬DOM VS MVVM?

相比起 React,其他 MVVM 系框架比如 Angular, Knockout 以及 Vue、Avalon 采用的都是數(shù)據(jù)綁定:通過(guò) 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):

  1. 臟檢查:scope digest + 必要 DOM 更新
  2. 依賴收集:重新收集依賴 + 必要 DOM 更新

可以看到,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)說(shuō)要昂貴很多。這里所有 MVVM 實(shí)現(xiàn)的一個(gè)共同問(wèn)題就是在列表渲染的數(shù)據(jù)源變動(dòng)時(shí),尤其是當(dāng)數(shù)據(jù)是全新的對(duì)象時(shí),如何有效地復(fù)用已經(jīng)創(chuàng)建的 ViewModel 實(shí)例和 DOM 元素。假如沒(méi)有任何復(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é)果沒(méi)變,那么就不需要做無(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)化過(guò)的在下面)

在比較性能的時(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。

  1. 初始渲染:Virtual DOM > 臟檢查 >= 依賴收集
  2. 小量數(shù)據(jù)更新:依賴收集 >> Virtual DOM + 優(yōu)化 > 臟檢查(無(wú)法優(yōu)化) > Virtual DOM 無(wú)優(yōu)化
  3. 大量數(shù)據(jù)更新:臟檢查 + 優(yōu)化 >= 依賴收集 + 優(yōu)化 > Virtual DOM(無(wú)法/無(wú)需優(yōu)化)>> MVVM 無(wú)優(yōu)化
  4. (該段落借鑒了知乎的相關(guān)回答)

四、對(duì)React虛擬DOM的誤解?

React 從來(lái)沒(méi)有說(shuō)過(guò) “React 比原生操作 DOM 快”。React給我們的保證是,在不需要手動(dòng)優(yōu)化的情況下,它依然可以給我們提供過(guò)得去的性能。

React掩蓋了底層的 DOM 操作,可以用更聲明式的方式來(lái)描述我們目的,從而讓代碼更容易維護(hù)。下面還是借鑒了知乎上的回答:沒(méi)有任何框架可以比純手動(dòng)的優(yōu)化 DOM 操作更快,因?yàn)榭蚣艿?DOM 操作層需要應(yīng)對(duì)任何上層 API 可能產(chǎn)生的操作,它的實(shí)現(xiàn)必須是普適的。針對(duì)任何一個(gè) benchmark,我都可以寫(xiě)出比任何框架更快的手動(dòng)優(yōu)化,但是那有什么意義呢?在構(gòu)建一個(gè)實(shí)際應(yīng)用的時(shí)候,你難道為每一個(gè)地方都去做手動(dòng)優(yōu)化嗎?出于可維護(hù)性的考慮,這顯然不可能。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 解決React報(bào)錯(cuò)JSX?element?type?does?not?have?any?construct?or?call?signatures

    解決React報(bào)錯(cuò)JSX?element?type?does?not?have?any?construct

    這篇文章主要為大家介紹了解決React報(bào)錯(cuò)JSX?element?type?does?not?have?any?construct?or?call?signatures,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 詳解react中的state的簡(jiǎn)寫(xiě)方式

    詳解react中的state的簡(jiǎn)寫(xiě)方式

    React是一個(gè)狀態(tài)機(jī)主要體現(xiàn)在state上,通過(guò)與用戶交易實(shí)現(xiàn)不同的狀態(tài),state是組件的私有屬性,是用來(lái)初始化的,本文重點(diǎn)給大家介紹react中的state的簡(jiǎn)寫(xiě)方式,感興趣的朋友一起看看吧
    2021-08-08
  • 使用react遍歷對(duì)象生成dom

    使用react遍歷對(duì)象生成dom

    這篇文章主要介紹了使用react遍歷對(duì)象生成dom問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • 學(xué)習(xí)ahooks useRequest并實(shí)現(xiàn)手寫(xiě)

    學(xué)習(xí)ahooks useRequest并實(shí)現(xiàn)手寫(xiě)

    這篇文章主要為大家介紹了學(xué)習(xí)ahooks useRequest并實(shí)現(xiàn)手寫(xiě)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Modal.confirm是否違反了React模式分析

    Modal.confirm是否違反了React模式分析

    這篇文章主要為大家介紹了Modal.confirm是否違反了React模式分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 詳解使用React.memo()來(lái)優(yōu)化函數(shù)組件的性能

    詳解使用React.memo()來(lái)優(yōu)化函數(shù)組件的性能

    本文講述了開(kāi)發(fā)React應(yīng)用時(shí)如何使用shouldComponentUpdate生命周期函數(shù)以及PureComponent去避免類組件進(jìn)行無(wú)用的重渲染,以及如何使用最新的React.memo API去優(yōu)化函數(shù)組件的性能
    2019-03-03
  • react時(shí)間分片實(shí)現(xiàn)流程詳解

    react時(shí)間分片實(shí)現(xiàn)流程詳解

    實(shí)現(xiàn)react時(shí)間分片,主要內(nèi)容包括什么是時(shí)間分片、為什么需要時(shí)間分片、實(shí)現(xiàn)分片開(kāi)啟 - 固定、實(shí)現(xiàn)分片中斷、重啟 - 連續(xù)、分片重啟、實(shí)現(xiàn)延遲執(zhí)行 - 有間隔、時(shí)間分片異步執(zhí)行方案的演進(jìn)、時(shí)間分片簡(jiǎn)單實(shí)現(xiàn)、總結(jié)、基本概念、基礎(chǔ)應(yīng)用、原理機(jī)制和需要注意的事項(xiàng)等
    2022-11-11
  • React RenderProps模式超詳細(xì)講解

    React RenderProps模式超詳細(xì)講解

    render props是指一種在 React 組件之間使用一個(gè)值為函數(shù)的 prop 共享代碼的技術(shù)。簡(jiǎn)單來(lái)說(shuō),給一個(gè)組件傳入一個(gè)prop,這個(gè)props是一個(gè)函數(shù),函數(shù)的作用是用來(lái)告訴這個(gè)組件需要渲染什么內(nèi)容,那么這個(gè)prop就成為render prop
    2022-11-11
  • React配置Redux并結(jié)合本地存儲(chǔ)設(shè)置token方式

    React配置Redux并結(jié)合本地存儲(chǔ)設(shè)置token方式

    這篇文章主要介紹了React配置Redux并結(jié)合本地存儲(chǔ)設(shè)置token方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 基于React封裝一個(gè)層次模糊效果的容器組件

    基于React封裝一個(gè)層次模糊效果的容器組件

    這篇文章主要為大家詳細(xì)介紹了如何基于React封裝一個(gè)層次模糊效果的容器組件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03

最新評(píng)論