日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

为什么需要虚拟DOM?

發(fā)布時(shí)間:2024/3/12 编程问答 74 豆豆
生活随笔 收集整理的這篇文章主要介紹了 为什么需要虚拟DOM? 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

  • 1. 真實(shí)DOM操作的性能問題
  • 2. 虛擬DOM的作用
  • 總結(jié)

我們知道,虛擬DOM的概念是由Facebook的React團(tuán)隊(duì)最早提出來(lái)的,也是React框架的核心概念之一。它的作用是以js的形式在內(nèi)存中描述真實(shí)的DOM結(jié)構(gòu),這樣當(dāng)頁(yè)面內(nèi)容需要發(fā)生變動(dòng)時(shí),React可以通過(guò)對(duì)前后虛擬DOM的比對(duì),計(jì)算出如何以最小的代價(jià)操作真實(shí)DOM。

1. 真實(shí)DOM操作的性能問題

在虛擬DOM出現(xiàn)之前,前端開發(fā)者最常用的方式是用jQuery直接操作真實(shí)DOM,像下面這樣:

<body><div id="root"></div><script>$('#root').text('這是一段文本');// 或者這種原生的方式// var root = document.querySelector('#root');// root.textContent = '這是一段文本';</script> </body>

在本例中,jQuery只是提供了一層對(duì)原生DOM操作的封裝。我們可以簡(jiǎn)單手寫一個(gè)$實(shí)現(xiàn):

function $ (selector) {this.nodeList = document.querySelectorAll(selector);return this; }$.prototype.text = function (textContent) {this.nodeList.forEach(node => {node.textContent = textContent;});return this; }

(本例只是用于解釋jQuery的封裝原理,并非jQuery的真實(shí)實(shí)現(xiàn))

通過(guò)這個(gè)簡(jiǎn)單的封裝我們可以發(fā)現(xiàn),jQuery的主要工作是提供對(duì)原生DOM操作的統(tǒng)一實(shí)現(xiàn)(另外還有對(duì)原生js的增強(qiáng),如ajax、動(dòng)畫等)。換句話說(shuō),使用jQuery,本質(zhì)上還是在直接操作真實(shí)DOM。

那么直接操作真實(shí)DOM有什么問題呢?

這就要從瀏覽器內(nèi)核的構(gòu)成說(shuō)起了。我們以webkit內(nèi)核為例,它大致包含以下模塊(圖片來(lái)自網(wǎng)絡(luò)):

首先來(lái)看左側(cè)的深色區(qū)域,它是webkit內(nèi)核的WebCore層。該區(qū)域左下角的HTML模塊代表HTML引擎,作用是解析HTML文檔。當(dāng)瀏覽器下載了一個(gè)HTML文檔后,它負(fù)責(zé)將該文檔解析成DOM樹,也就是由一個(gè)個(gè)標(biāo)簽節(jié)點(diǎn)構(gòu)成的文檔樹。最終解析出來(lái)的DOM樹將交由它右側(cè)的DOM模塊負(fù)責(zé)管理,而這個(gè)DOM樹就是我們平常所說(shuō)的真實(shí)DOM。

在深色區(qū)域的右側(cè)緊鄰著的是JavaScriptCore,即webkit默認(rèn)的JavaScript引擎(在Chrome和chromium中它被替換為了V8),它負(fù)責(zé)執(zhí)行JavaScript代碼。

我們知道,JavaScript具備操作DOM樹的能力。但是從瀏覽器內(nèi)核的結(jié)構(gòu)可以看到,DOM樹由DOM模塊負(fù)責(zé)管理,在瀏覽器內(nèi)核中單獨(dú)占有一塊內(nèi)存,而這塊內(nèi)存與JavaScript引擎所管理的內(nèi)存并無(wú)直接關(guān)系。換句話說(shuō),JavaScript引擎不能直接操作真實(shí)DOM樹。

為了給JavaScript提供操作DOM樹的能力,瀏覽器在全局對(duì)象window上為JavaScript封裝了一個(gè)document對(duì)象,然后在該對(duì)象上提供了大量的DOM操作接口,這些接口都是用C++實(shí)現(xiàn)的。如:

在瀏覽器控制臺(tái)查看document.getElementById,可以看到它的函數(shù)體是{ [native code] },這表示它是一個(gè)用C++編寫的函數(shù),因此無(wú)法查看具體實(shí)現(xiàn)。當(dāng)我們?cè)谡{(diào)用這個(gè)函數(shù)時(shí),JavaScript引擎并沒有直接與DOM模塊交互,而是由瀏覽器來(lái)操作DOM模塊,隨后再把操作結(jié)果返回給JavaScript引擎。這種借助父級(jí)模塊實(shí)現(xiàn)兩個(gè)同級(jí)模塊交互的通信方式非常常見。

正是由于JavaScript需要借助瀏覽器提供的DOM接口才能操作真實(shí)DOM,所以操作真實(shí)DOM的代價(jià)往往是比較大的(這其中還涉及C++與JavaScript數(shù)據(jù)結(jié)構(gòu)的轉(zhuǎn)換問題)。再加上修改DOM經(jīng)常導(dǎo)致頁(yè)面重繪,所以一般來(lái)說(shuō),DOM操作越多,網(wǎng)頁(yè)的性能就越差。我們以一個(gè)簡(jiǎn)單的圖例來(lái)理解這個(gè)過(guò)程:

有人可能會(huì)問,既然DOM操作的代價(jià)如此之大,為什么不由JavaScript引擎來(lái)管理DOM呢?不要忘了,世界上第一款瀏覽器誕生于1990年,那時(shí)候就已經(jīng)出現(xiàn)了DOM的原始概念,而JavaScript則直到1995年才誕生。換句話說(shuō),DOM的出現(xiàn)早于JavaScript。因此,如果要由JavaScript來(lái)管理DOM,那就意味著瀏覽器內(nèi)核必須重構(gòu)。而讓瀏覽器開發(fā)者為了一個(gè)早期被稱為“玩具語(yǔ)言”的JavaScript重構(gòu)瀏覽器內(nèi)核顯然是不可能的。不過(guò)隨著JavaScript的發(fā)展,由JavaScript引擎直接管理DOM的構(gòu)想已經(jīng)被提上了chromium的計(jì)劃列表(目前只是定為長(zhǎng)期計(jì)劃,要真正實(shí)現(xiàn)還需要相當(dāng)長(zhǎng)的時(shí)間)。

所以,截止到目前,如何有效地減少對(duì)真實(shí)DOM的操作,仍然是前端性能優(yōu)化的一個(gè)關(guān)鍵點(diǎn)。虛擬DOM就是目前較為流行的一個(gè)解決方案。

2. 虛擬DOM的作用

顯然,JavaScript無(wú)法直接操作DOM是帶來(lái)上述性能問題的根源之一(其他原因包括,真實(shí)DOM樹的體積非常龐大,而且操作它會(huì)導(dǎo)致頁(yè)面重繪)。那么能不能在JavaScript內(nèi)存中,以js對(duì)象的形式也描述一棵DOM樹呢?當(dāng)然可以,這就是我們所說(shuō)的虛擬DOM樹。

可以看到,虛擬DOM并不能消除原生的DOM操作,你仍然需要通過(guò)瀏覽器提供的DOM接口來(lái)操作真實(shí)DOM樹,才能使頁(yè)面發(fā)生改變。虛擬DOM的設(shè)計(jì)似乎是多此一舉。

但是虛擬DOM帶來(lái)了一個(gè)重要的優(yōu)勢(shì),那就是我們可以在完全不訪問真實(shí)DOM的情況下,掌握DOM的結(jié)構(gòu),這為框架自動(dòng)優(yōu)化DOM操作提供了可能。舉例來(lái)說(shuō),如果我們本打算手動(dòng)進(jìn)行三次真實(shí)DOM操作,而框架在分析了虛擬DOM的結(jié)構(gòu)后,把這三次DOM操作簡(jiǎn)化成了一次,這不就帶來(lái)了性能上的提升嗎?再甚者,如果連這一次DOM操作都可以由框架自動(dòng)完成(自動(dòng)更新的前提是我們要定義視圖和數(shù)據(jù)的綁定關(guān)系),而我們只需要負(fù)責(zé)處理數(shù)據(jù),那么虛擬DOM的價(jià)值體現(xiàn)得就更明顯了。

React就是這么使用虛擬DOM的。

當(dāng)我們使用jsx語(yǔ)法定義一個(gè)模板時(shí),React會(huì)用它生成一個(gè)由JavaScript描述的虛擬DOM樹,并將其保存在JavaScript內(nèi)存中。這個(gè)虛擬DOM樹還保留了我們?cè)谀0逯卸x的數(shù)據(jù)和視圖的綁定關(guān)系,這為React自動(dòng)根據(jù)數(shù)據(jù)變化更新視圖提供了可能。隨后當(dāng)數(shù)據(jù)發(fā)生變化時(shí),React重新生成一個(gè)虛擬DOM樹,通過(guò)對(duì)比兩個(gè)虛擬DOM樹的差異,React就可以知道該如何高效地更新視圖。接著它就會(huì)調(diào)用原生的DOM接口,去更新真實(shí)DOM。過(guò)程大致如下:

對(duì)于開發(fā)者而言,虛擬DOM的實(shí)現(xiàn)是透明的,它只是框架自動(dòng)高效更新DOM的一種內(nèi)部解決方案。開發(fā)者需要按照框架給定的語(yǔ)法定義數(shù)據(jù)和視圖的綁定關(guān)系,隨后就只需要關(guān)心數(shù)據(jù)變化(即業(yè)務(wù)邏輯)即可。

當(dāng)然了,虛擬DOM并不是解決DOM操作性能問題的唯一解決方案,Vue的響應(yīng)式系統(tǒng)也是一種重要的解決方案。從某種程度上來(lái)說(shuō),Vue依靠響應(yīng)式系統(tǒng)可以實(shí)現(xiàn)“精確定點(diǎn)更新”,即直接定位到哪個(gè)DOM節(jié)點(diǎn)需要更新,而不需要經(jīng)過(guò)虛擬DOM的比對(duì),不過(guò)“精確定點(diǎn)更新”的內(nèi)存代價(jià)偏大,因此目前Vue采用了響應(yīng)式系統(tǒng)和虛擬DOM結(jié)合的方式,本文暫不詳述。

最后我們來(lái)看一下Vue中虛擬DOM樹的結(jié)構(gòu),實(shí)際上它就是一個(gè)js對(duì)象而已,我們以下面的模板為例:

<template><div id="app"><ul><li v-for=“item in items”>itemid: {{ item.id }}</li></ul></div> </template>

對(duì)應(yīng)的虛擬DOM:

總結(jié)

要理解為什么需要虛擬DOM,必須弄清楚JavaScript引擎和DOM模塊之間的關(guān)系,并體會(huì)由這種關(guān)系導(dǎo)致的DOM操作的性能問題。虛擬DOM設(shè)計(jì)的核心就是用高效的js操作,來(lái)減少低性能的DOM操作,以此來(lái)提升網(wǎng)頁(yè)性能。

從一定程度上來(lái)說(shuō),是瀏覽器的架構(gòu)問題催生了虛擬DOM,而這個(gè)架構(gòu)問題幾乎需要重構(gòu)瀏覽器內(nèi)核才能解決,所以目前虛擬DOM仍廣為流行。如果未來(lái)的某一天,真實(shí)DOM被遷移到JavaScript內(nèi)存中,虛擬DOM的價(jià)值實(shí)際上也就不存在了。

總結(jié)

以上是生活随笔為你收集整理的为什么需要虚拟DOM?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。