国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

前端性能優(yōu)化之瀏覽器渲染優(yōu)化

這篇具有很好參考價(jià)值的文章主要介紹了前端性能優(yōu)化之瀏覽器渲染優(yōu)化。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

引言

在當(dāng)今互聯(lián)網(wǎng)高速發(fā)展的時(shí)代,用戶對(duì)于網(wǎng)頁(yè)加載速度和性能的要求越來(lái)越高。作為前端開(kāi)發(fā)者,我們需要關(guān)注并致力于提升網(wǎng)頁(yè)的加載和渲染性能,以提供更好的用戶體驗(yàn)。而瀏覽器渲染優(yōu)化正是我們實(shí)現(xiàn)這個(gè)目標(biāo)的關(guān)鍵。在本文中,我們將探討一些關(guān)于瀏覽器渲染優(yōu)化的技巧和策略,旨在幫助您優(yōu)化網(wǎng)頁(yè)的渲染過(guò)程,提高頁(yè)面的加載速度和性能。無(wú)論您是剛?cè)腴T的前端開(kāi)發(fā)者還是有經(jīng)驗(yàn)的資深開(kāi)發(fā)者,本文都將為您提供一些寶貴的建議和實(shí)用的技巧,讓您的網(wǎng)頁(yè)在瀏覽器中獲得更快的渲染速度。讓我們一起探索如何通過(guò)瀏覽器渲染優(yōu)化來(lái)提升網(wǎng)頁(yè)性能吧!

一、瀏覽器渲染流程

瀏覽器渲染流程是指瀏覽器將從服務(wù)器獲取到的HTML、CSS和JavaScript等資源解析、布局、繪制并最終展示給用戶的過(guò)程。下面是一個(gè)瀏覽器渲染的簡(jiǎn)單流程示意圖:

  1. 解析HTML:瀏覽器會(huì)從頂部開(kāi)始解析HTML文檔,構(gòu)建一棵DOM(文檔對(duì)象模型)樹(shù)。DOM樹(shù)表示了HTML文檔的結(jié)構(gòu),包括標(biāo)簽、屬性和文本節(jié)點(diǎn)等。

  2. 解析CSS:瀏覽器會(huì)解析外部CSS文件,并將樣式規(guī)則應(yīng)用于DOM樹(shù)中的相應(yīng)元素。解析CSS的過(guò)程會(huì)生成一棵CSSOMCSS對(duì)象模型)樹(shù),它與DOM樹(shù)相似,但表示了CSS樣式信息。

  3. 構(gòu)建渲染樹(shù)(Render Tree):瀏覽器將DOM樹(shù)和CSSOM樹(shù)合并,構(gòu)建一棵渲染樹(shù)。渲染樹(shù)只包含需要顯示在頁(yè)面中的可見(jiàn)元素,例如不可見(jiàn)的元素(如display:none)不會(huì)被包含在渲染樹(shù)中。

  4. 布局(Layout):瀏覽器會(huì)計(jì)算渲染樹(shù)中每個(gè)元素在頁(yè)面中的大小和位置,確定它們的盒模型(Box Model)信息。這個(gè)過(guò)程叫做布局或回流(reflow),它會(huì)根據(jù)一些CSS屬性(如width、height、position等)來(lái)計(jì)算每個(gè)元素的準(zhǔn)確位置。

  5. 繪制(Paint):瀏覽器根據(jù)渲染樹(shù)和布局的信息,開(kāi)始將每個(gè)元素繪制到屏幕上。繪制的過(guò)程會(huì)將每個(gè)元素轉(zhuǎn)換為一個(gè)或多個(gè)圖層,并使用GPU加速技術(shù)來(lái)提高性能。

  6. 柵格化(Rasterization):在繪制完成后,瀏覽器會(huì)將圖層切分成小的圖塊,并將它們轉(zhuǎn)換為位圖。這個(gè)過(guò)程叫做柵格化,它將圖形轉(zhuǎn)換為可以在屏幕上顯示的像素。

  7. 合成(Composition):瀏覽器將所有圖塊按照正確的順序合成,并輸出最終的渲染結(jié)果。這個(gè)過(guò)程叫做合成,它會(huì)將位圖繪制到屏幕上,并根據(jù)用戶的交互操作來(lái)不斷更新渲染結(jié)果。

整個(gè)過(guò)程可以以流程圖的形式展示如下:

開(kāi)始 -> 解析HTML -> 樣式計(jì)算 -> 布局計(jì)算 -> 繪制 -> 合成 -> 結(jié)束

總結(jié)來(lái)說(shuō),瀏覽器渲染流程包括解析HTML、解析CSS、構(gòu)建渲染樹(shù)、布局、繪制、柵格化和合成等步驟。這些步驟將HTML、CSSJavaScript轉(zhuǎn)換為可見(jiàn)的網(wǎng)頁(yè)內(nèi)容,讓用戶能夠正常瀏覽網(wǎng)頁(yè)。

在這里補(bǔ)充一點(diǎn)
在瀏覽器渲染流程的最后一步,合成(Composition)主要做以下工作

  1. 對(duì)渲染樹(shù)進(jìn)行合成:合成引擎會(huì)根據(jù)渲染樹(shù)的結(jié)構(gòu)和樣式屬性信息,將頁(yè)面元素組合為一層或多層圖層。這些圖層可以根據(jù)需要進(jìn)行獨(dú)立地繪制和合成。

  2. 圖層的繪制:在合成階段,合成引擎會(huì)將每個(gè)圖層分別繪制成位圖。這個(gè)過(guò)程通常發(fā)生在GPU中,利用硬件加速能力來(lái)加快繪制速度。

  3. 圖層的合成:合成引擎將繪制好的圖層按照正確的順序進(jìn)行合成。合成過(guò)程會(huì)將不同圖層的位圖進(jìn)行透明度混合、遮罩等操作,最終生成待顯示的全局位圖。

  4. 顯示和顯示列表更新:最后,合成引擎將生成的全局位圖通過(guò)顯示管道交給顯示器進(jìn)行顯示。同時(shí),合成引擎還會(huì)更新頁(yè)面的顯示列表,以反映最新的渲染結(jié)果。

總之,合成(Composition)是瀏覽器渲染流程的最后一步,它包括對(duì)渲染樹(shù)進(jìn)行合成、圖層的繪制和合成、最終位圖的生成和顯示列表的更新等步驟,最終將渲染結(jié)果顯示在用戶的屏幕上。這些工作有助于提高渲染性能和用戶體驗(yàn)。

二、回流

1. 什么是回流

回流(reflow)是指瀏覽器重新渲染部分或全部的頁(yè)面布局,當(dāng)頁(yè)面的結(jié)構(gòu)、樣式或者布局屬性發(fā)生變化時(shí),瀏覽器會(huì)觸發(fā)回流。

回流發(fā)生在瀏覽器渲染的過(guò)程中的布局階段。在渲染過(guò)程中有兩個(gè)主要步驟:布局(layout)和繪制(painting)。

布局階段是指瀏覽器根據(jù)元素的盒模型計(jì)算出每個(gè)元素在頁(yè)面中的位置和大小,建立元素之間的關(guān)系,并生成布局樹(shù)(render tree)。當(dāng)瀏覽器在布局階段發(fā)現(xiàn)頁(yè)面結(jié)構(gòu)或者樣式發(fā)生變化時(shí),就會(huì)觸發(fā)回流。

在回流過(guò)程中,瀏覽器會(huì)遍歷布局樹(shù),計(jì)算每個(gè)元素的位置和大小,并更新相應(yīng)的渲染信息,然后重新生成布局樹(shù)和繪制樹(shù),最后進(jìn)行繪制。

需要注意的是,回流是一個(gè)相對(duì)耗費(fèi)性能的操作,因?yàn)楫?dāng)回流發(fā)生時(shí),瀏覽器需要重新計(jì)算頁(yè)面布局,并更新相關(guān)的渲染信息。頻繁的回流會(huì)導(dǎo)致頁(yè)面的性能下降,因此在開(kāi)發(fā)中應(yīng)該盡量減少回流的發(fā)生,以提高頁(yè)面的性能。

2. 哪些操作會(huì)導(dǎo)致回流

瀏覽器渲染回流(reflow)指的是當(dāng)頁(yè)面布局和幾何屬性發(fā)生改變時(shí),瀏覽器會(huì)重新計(jì)算元素的布局并重新繪制,這個(gè)過(guò)程會(huì)消耗很多性能。以下是一些常見(jiàn)的操作會(huì)導(dǎo)致瀏覽器渲染回流的情況:

  1. 改變窗口大小:當(dāng)窗口大小改變時(shí),頁(yè)面布局會(huì)發(fā)生變化,需要重新計(jì)算元素的布局并重新繪制。
window.addEventListener('resize', function () {
  // 窗口大小改變的操作
});
  1. 改變?cè)爻叽?/strong>:當(dāng)改變?cè)氐膶挾?、高度、?nèi)外邊距等屬性時(shí),會(huì)觸發(fā)瀏覽器重新計(jì)算元素的布局。
element.style.width = "200px";
element.style.height = "100px";
  1. 改變?cè)匚恢?/strong>:當(dāng)改變?cè)氐奈恢脤傩裕╰op、left、right、bottom)時(shí),會(huì)導(dǎo)致其周圍元素的重新布局。
element.style.position = "absolute";
element.style.left = "100px";
element.style.top = "50px";
  1. 添加或刪除元素:當(dāng)添加或刪除元素時(shí),會(huì)導(dǎo)致整個(gè)頁(yè)面布局發(fā)生變化,所有元素都需要重新計(jì)算布局。
document.body.appendChild(newElement);
document.body.removeChild(elementToRemove);
  1. 修改元素的內(nèi)容:當(dāng)修改元素的文本內(nèi)容或HTML結(jié)構(gòu)時(shí),會(huì)導(dǎo)致元素及其周圍元素的重新布局。
element.textContent = "New Content";
element.innerHTML = "<p>New HTML</p>";
  1. 計(jì)算某些屬性:當(dāng)獲取一些計(jì)算屬性(如offsetWidth、offsetHeight、clientWidth、clientHeight等)時(shí),瀏覽器需要重新計(jì)算元素的布局。
var width = element.offsetWidth;
var height = element.offsetHeight;

三. 針對(duì)回流如何優(yōu)化

回流(reflow)是瀏覽器對(duì)網(wǎng)頁(yè)布局進(jìn)行重新計(jì)算和重新繪制的過(guò)程,它是一種非常消耗性能的操作。優(yōu)化回流可以提高網(wǎng)頁(yè)的渲染性能,以下是一些常用的方法:

1. 使用transform和opacity代替top、left和width等屬性來(lái)進(jìn)行動(dòng)畫(huà)效果的實(shí)現(xiàn)。因?yàn)閠ransform和opacity不會(huì)引起回流。

假設(shè)有一個(gè)按鈕,希望在點(diǎn)擊時(shí)顯示一個(gè)動(dòng)畫(huà)效果,可以使用transformopacity來(lái)實(shí)現(xiàn)而不使用top、leftwidth等屬性。以下是一個(gè)實(shí)際案例的示例:

HTML結(jié)構(gòu):

<button id="myButton">點(diǎn)擊我</button>

CSS樣式:

#myButton {
  position: relative;
  padding: 10px 20px;
  background-color: blue;
  color: white;
  transform: scale(1);
  opacity: 1;
  transition: transform 0.3s, opacity 0.3s;
}

#myButton.clicked {
  transform: scale(0.8);
  opacity: 0;
}

JavaScript代碼:

var button = document.getElementById("myButton");
button.addEventListener("click", function() {
  button.classList.add("clicked");
});

在上面的示例中,按鈕元素默認(rèn)具有初始的transformopacity屬性。當(dāng)按鈕被點(diǎn)擊時(shí),通過(guò)添加clicked類來(lái)觸發(fā)動(dòng)畫(huà)效果。這個(gè)類會(huì)改變按鈕的transformopacity屬性,從而實(shí)現(xiàn)縮放和逐漸消失的效果。

由于transformopacity屬性的改變不會(huì)引起回流(reflow),這種動(dòng)畫(huà)方式可以提供更流暢的用戶體驗(yàn),尤其是在處理復(fù)雜的動(dòng)畫(huà)效果時(shí)。

2. 盡量使用絕對(duì)定位(position: absolute)來(lái)移動(dòng)元素,而不是修改元素的布局屬性。因?yàn)榻^對(duì)定位會(huì)脫離文檔流,不會(huì)引起其他元素的重新布局。

使用絕對(duì)定位(position: absolute)可以將元素移出正常文檔流并進(jìn)行精確的定位,從而避免回流。

下面是一個(gè)實(shí)際案例的示例:

HTML代碼如下:

<div class="container">
  <div class="box"></div>
</div>

CSS樣式如下:

.container {
  position: relative;
  width: 300px;
  height: 200px;
  border: 1px solid #000;
}

.box {
  position: absolute;
  top: 50px;
  left: 50px;
  width: 100px;
  height: 100px;
  background-color: red;
}

在這個(gè)案例中,.container 是一個(gè)相對(duì)定位的父容器,.box 是一個(gè)絕對(duì)定位的子元素。通過(guò)設(shè)置 .boxtop 值和 left 值,可以精確地將其定位到 .container 的指定位置。

這樣,當(dāng)改變 .box 元素的位置時(shí),并不會(huì)導(dǎo)致父容器 .container 的大小或其他元素的布局屬性發(fā)生改變,從而避免了回流的發(fā)生。

總結(jié):

  • 設(shè)置父容器(.container)的 positionrelative,以創(chuàng)建一個(gè)相對(duì)定位的參照點(diǎn)。
  • 設(shè)置子元素(.box)的 positionabsolute,以將其位置脫離正常文檔流。
  • 使用 topleft 屬性來(lái)精確地定位子元素的位置。

這樣,通過(guò)使用絕對(duì)定位,可以移動(dòng)元素而不改變其布局屬性,從而避免回流的發(fā)生。

3. 避免使用table布局,因?yàn)閠able的每個(gè)單元格的內(nèi)容變化都會(huì)引起回流??梢允褂肅SS的display: table和display: table-cell來(lái)實(shí)現(xiàn)類似的效果。

一個(gè)常見(jiàn)的使用table布局的場(chǎng)景是創(chuàng)建一個(gè)水平居中的導(dǎo)航菜單,其中每個(gè)菜單項(xiàng)的寬度是根據(jù)內(nèi)容動(dòng)態(tài)調(diào)整的。

使用table布局的代碼可能如下所示:

<table class="nav">
  <tr>
    <td>菜單項(xiàng)1</td>
    <td>菜單項(xiàng)2</td>
    <td>菜單項(xiàng)3</td>
    <td>菜單項(xiàng)4</td>
  </tr>
</table>

但是,這種布局方式會(huì)引起回流,因?yàn)槊總€(gè)單元格的寬度需要根據(jù)內(nèi)容動(dòng)態(tài)調(diào)整。

一種避免使用table布局的方法是使用CSS的display: tabledisplay: table-cell屬性來(lái)實(shí)現(xiàn)類似的效果,同時(shí)避免回流。代碼如下所示:

<div class="nav">
  <div class="nav-item">菜單項(xiàng)1</div>
  <div class="nav-item">菜單項(xiàng)2</div>
  <div class="nav-item">菜單項(xiàng)3</div>
  <div class="nav-item">菜單項(xiàng)4</div>
</div>
.nav {
  display: table;
  width: 100%;
}

.nav-item {
  display: table-cell;
  text-align: center;
}

.nav-item:hover {
  background-color: gray;
}

在這個(gè)例子中,使用了一個(gè)<div>元素作為導(dǎo)航菜單的容器,通過(guò)設(shè)置display: table來(lái)模擬表格布局的效果,每個(gè)菜單項(xiàng)則使用display: table-cell來(lái)模擬表格中的單元格。

這樣做的好處是,每個(gè)菜單項(xiàng)的寬度會(huì)根據(jù)內(nèi)容自適應(yīng),而不會(huì)引起回流。另外,還可以使用CSS來(lái)為菜單項(xiàng)添加樣式,比如當(dāng)鼠標(biāo)懸停時(shí)改變背景顏色。

總之,通過(guò)使用display: tabledisplay: table-cell屬性來(lái)模擬表格布局,可以避免回流,并且能夠更靈活地控制布局和樣式。

4. 避免在循環(huán)中多次修改DOM元素的樣式,可以先把需要修改的樣式保存在變量中,然后一次性地更新DOM元素的樣式。

以修改一個(gè)列表中所有元素的樣式為例,假設(shè)有一個(gè)<ul>元素,并希望將其中所有的<li>元素的背景顏色設(shè)置為紅色。如果在循環(huán)中多次修改DOM元素的樣式,會(huì)導(dǎo)致多次回流,影響性能。

下面是一種避免回流的方式,先將需要修改的樣式保存在一個(gè)對(duì)象中,然后一次性地更新DOM元素的樣式:

// 獲取<ul>元素
const list = document.querySelector('ul');

// 創(chuàng)建一個(gè)對(duì)象,存儲(chǔ)需要修改的樣式
const styles = {
  backgroundColor: 'red'
};

// 循環(huán)遍歷所有的<li>元素
const items = list.getElementsByTagName('li');
for(let i = 0; i < items.length; i++) {
  // 將需要修改的樣式應(yīng)用到每個(gè)<li>元素
  Object.assign(items[i].style, styles);
}

通過(guò)上述代碼可以看到,首先使用querySelector獲取到要操作的<ul>元素,然后創(chuàng)建一個(gè)styles對(duì)象,該對(duì)象存儲(chǔ)需要修改的樣式,此處只設(shè)置背景顏色為紅色。接下來(lái)使用getElementsByTagName獲取到所有的<li>元素,并通過(guò)循環(huán)遍歷將存儲(chǔ)的樣式應(yīng)用到每個(gè)<li>元素上,通過(guò)Object.assign方法將styles對(duì)象上的樣式屬性一次性賦值給li元素的style屬性。

這樣就實(shí)現(xiàn)了將所有<li>元素的背景顏色設(shè)置為紅色的效果,避免了在循環(huán)中多次修改DOM元素的樣式,減少了回流的次數(shù),提高了性能。

5. 避免頻繁地讀取布局屬性(如offsetWidth、offsetHeight等),可以把這些屬性的值緩存起來(lái)使用。

在實(shí)際開(kāi)發(fā)中,頻繁地讀取布局屬性(如offsetWidth、offsetHeight等)會(huì)導(dǎo)致瀏覽器頻繁進(jìn)行回流(reflow),影響頁(yè)面性能。為了避免這種情況,可以將這些屬性的值緩存起來(lái)使用。

一個(gè)實(shí)際案例是在滾動(dòng)時(shí)獲取元素的高度。在某些場(chǎng)景下,我們需要獲取元素的高度進(jìn)行處理,但是如果在每次滾動(dòng)事件中都直接調(diào)用offsetHeight來(lái)獲取高度,就會(huì)導(dǎo)致頻繁的回流。

為了避免這種情況,我們可以在頁(yè)面加載或元素渲染完成后,將元素的高度緩存起來(lái),而不是每次滾動(dòng)事件中都去讀取。

示例代碼如下:

// 獲取元素
const element = document.getElementById('scrollElement');

// 緩存元素的高度
let cachedHeight = element.offsetHeight;

// 監(jiān)聽(tīng)滾動(dòng)事件
window.addEventListener('scroll', () => {
  // 使用緩存的高度進(jìn)行處理
  // ...
});

在上述代碼中,我們?cè)陧?yè)面加載或元素渲染完成后,將元素的高度緩存在cachedHeight變量中。然后,當(dāng)滾動(dòng)事件觸發(fā)時(shí),我們直接使用緩存的高度進(jìn)行處理,而不是每次都調(diào)用offsetHeight獲取高度。

這樣做可以避免頻繁地讀取布局屬性,減少回流的次數(shù),提升頁(yè)面性能。需要注意的是,在一些特殊情況下,如元素高度會(huì)發(fā)生動(dòng)態(tài)變化的情況下,需要及時(shí)更新緩存的高度。

6. 使用虛擬DOM技術(shù),例如React和Vue.js等框架,在組件更新時(shí)只更新變化的部分,而不是整個(gè)DOM樹(shù)。

使用虛擬DOM技術(shù)的框架,如React和Vue.js,可以通過(guò)比較虛擬DOM樹(shù)的變化來(lái)更新實(shí)際DOM樹(shù)的部分而避免回流。

舉一個(gè)實(shí)際案例來(lái)說(shuō)明,假設(shè)我們有一個(gè)用戶列表,其中包含多個(gè)用戶信息的組件。我們要實(shí)現(xiàn)一個(gè)簡(jiǎn)單的用戶搜索功能,用戶輸入關(guān)鍵字后,列表應(yīng)該顯示匹配到的用戶信息。

首先,在React中,我們可以定義一個(gè)UserList組件來(lái)渲染用戶列表:

class UserList extends React.Component {
  render() {
    return (
      <div>
        {this.props.users.map(user => (
          <UserItem key={user.id} user={user} />
        ))}
      </div>
    );
  }
}

在Vue.js中也類似:

Vue.component('user-list', {
  props: ['users'],
  template: `
    <div>
      <user-item v-for="user in users" :key="user.id" :user="user" />
    </div>
  `,
});

UserItem組件是用來(lái)顯示單個(gè)用戶信息的組件,我們可以在該組件中加入一個(gè)輸入框,用來(lái)輸入搜索關(guān)鍵字:

class UserItem extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      search: '',
    };
  }

  handleSearchChange = (event) => {
    this.setState({ search: event.target.value });
  }

  render() {
    const { user } = this.props;
    const { search } = this.state;

    return (
      <div>
        <h3>{user.name}</h3>
        <p>{user.email}</p>
        <input type="text" value={search} onChange={this.handleSearchChange} />
      </div>
    );
  }
}

在Vue.js中,我們也可以實(shí)現(xiàn)類似的邏輯:

Vue.component('user-item', {
  props: ['user'],
  data() {
    return {
      search: '',
    };
  },
  methods: {
    handleSearchChange(event) {
      this.search = event.target.value;
    },
  },
  template: `
    <div>
      <h3>{{ user.name }}</h3>
      <p>{{ user.email }}</p>
      <input type="text" v-model="search" />
    </div>
  `,
});

現(xiàn)在,每當(dāng)用戶在任意一個(gè)輸入框中輸入關(guān)鍵字時(shí),都會(huì)更新對(duì)應(yīng)的組件的search狀態(tài)。由于React和Vue.js使用虛擬DOM的技術(shù),它們會(huì)比較前后兩個(gè)虛擬DOM樹(shù)的差異,并只更新變化的部分到實(shí)際DOM樹(shù)中。

這里,我們只需要在UserItem組件中根據(jù)搜索關(guān)鍵字來(lái)動(dòng)態(tài)顯示用戶信息即可。例如,在React中:

class UserItem extends React.Component {
  // ...

  render() {
    const { user } = this.props;
    const { search } = this.state;

    if (search && !user.name.toLowerCase().includes(search.toLowerCase())) {
      // 不匹配搜索關(guān)鍵字時(shí),返回null,不渲染該用戶信息
      return null;
    }

    return (
      <div>
        <h3>{user.name}</h3>
        <p>{user.email}</p>
        <input type="text" value={search} onChange={this.handleSearchChange} />
      </div>
    );
  }
}

在Vue.js中,可以使用v-if指令來(lái)實(shí)現(xiàn)類似的邏輯:

Vue.component('user-item', {
  // ...

  template: `
    <div v-if="!search || user.name.toLowerCase().includes(search.toLowerCase())">
      <h3>{{ user.name }}</h3>
      <p>{{ user.email }}</p>
      <input type="text" v-model="search" />
    </div>
  `,
});

這樣,每當(dāng)用戶輸入關(guān)鍵字搜索時(shí),只會(huì)更新匹配到的用戶信息的部分,而不是整個(gè)DOM樹(shù)。這樣就避免了不必要的回流,提高了性能。

7. 使用CSS的will-change屬性來(lái)提前告訴瀏覽器某個(gè)元素即將被修改,并且瀏覽器可以對(duì)該元素進(jìn)行一些優(yōu)化。

將元素的will-change屬性設(shè)置為某個(gè)屬性,可以告訴瀏覽器該元素即將被修改,并且瀏覽器可以對(duì)該元素進(jìn)行一些優(yōu)化,以避免回流。這樣可以提高性能,避免不必要的布局計(jì)算。

下面是一個(gè)使用will-change屬性的實(shí)際案例:

HTML:

<div class="box">這是一個(gè) Box</div>

CSS:

.box {
  width: 100px;
  height: 100px;
  background-color: red;
  transition: transform 1s ease-in-out;
}

.box:hover {
  transform: scale(1.2);
  will-change: transform;
}

在這個(gè)案例中,當(dāng)鼠標(biāo)懸停在box元素上時(shí),元素將會(huì)發(fā)生縮放效果。我們將.box:hover選擇器中的will-change屬性設(shè)置為transform,告訴瀏覽器元素即將被修改的是transform屬性。

這樣,瀏覽器就會(huì)知道在box元素發(fā)生縮放之前要做一些優(yōu)化,以避免不必要的回流。例如,在修改transform之前,瀏覽器可以準(zhǔn)備好渲染層,以防止布局重新計(jì)算。

使用will-change屬性可以提高性能,特別是在處理需要改變的大型元素或復(fù)雜動(dòng)畫(huà)時(shí)。然而,濫用will-change屬性可能會(huì)導(dǎo)致性能問(wèn)題,因此應(yīng)確保僅應(yīng)用于必要的元素和屬性。

8. 避免頻繁地修改DOM樹(shù)的結(jié)構(gòu),可以采用一些優(yōu)化策略,例如使用文檔片段(DocumentFragment)進(jìn)行批量插入和刪除操作,或者使用字符串拼接的方式生成HTML代碼。

documentFragment
在實(shí)際案例中,假設(shè)有一個(gè)待辦事項(xiàng)列表,用戶可以添加、刪除和完成任務(wù)。每當(dāng)用戶進(jìn)行這些操作時(shí),會(huì)修改DOM樹(shù)的結(jié)構(gòu),可能會(huì)導(dǎo)致頻繁的回流和重繪,降低性能和用戶體驗(yàn)。

為了避免頻繁地修改DOM樹(shù)的結(jié)構(gòu),我們可以使用文檔片段進(jìn)行批量插入和刪除操作。文檔片段是一個(gè)輕量級(jí)的DOM節(jié)點(diǎn)容器,可以包含一組節(jié)點(diǎn),但不會(huì)在文檔中創(chuàng)建真實(shí)的節(jié)點(diǎn)。

以下是一個(gè)使用文檔片段進(jìn)行批量插入的實(shí)際案例:

// 創(chuàng)建一個(gè)文檔片段
var fragment = document.createDocumentFragment();

// 獲取待辦事項(xiàng)列表的容器元素
var container = document.getElementById('todoList');

// 待添加的任務(wù)數(shù)據(jù)
var tasks = ['任務(wù)1', '任務(wù)2', '任務(wù)3'];

// 循環(huán)遍歷任務(wù)列表
tasks.forEach(function(task) {
  // 創(chuàng)建新的任務(wù)元素
  var item = document.createElement('li');
  item.textContent = task;
  
  // 將任務(wù)元素添加到文檔片段中
  fragment.appendChild(item);
});

// 將文檔片段一次性插入到容器中
container.appendChild(fragment);

在這個(gè)案例中,我們先創(chuàng)建一個(gè)文檔片段 fragment,然后循環(huán)遍歷任務(wù)列表,創(chuàng)建新的任務(wù)元素并將其添加到文檔片段中。最后,通過(guò)一次性地將文檔片段插入到容器中,避免了頻繁地修改DOM樹(shù)結(jié)構(gòu),減少了回流的次數(shù)。

同樣地,我們可以使用文檔片段進(jìn)行批量刪除操作。以下是一個(gè)使用文檔片段進(jìn)行批量刪除的實(shí)際案例:

// 創(chuàng)建一個(gè)文檔片段
var fragment = document.createDocumentFragment();

// 獲取待刪除的任務(wù)元素列表
var deleteList = document.querySelectorAll('.delete');

// 遍歷待刪除的任務(wù)元素列表
Array.prototype.forEach.call(deleteList, function(item) {
  // 將任務(wù)元素從文檔中移除并添加到文檔片段中
  fragment.appendChild(item);
});

// 從容器中一次性刪除文檔片段中的任務(wù)元素
container.removeChild(fragment);

在這個(gè)案例中,我們先創(chuàng)建一個(gè)文檔片段 fragment,然后通過(guò)querySelectorAll獲取待刪除的任務(wù)元素列表。接著,我們遍歷這個(gè)列表,將每個(gè)任務(wù)元素從文檔中移除并添加到文檔片段中。最后,通過(guò)一次性地將文檔片段從容器中刪除,避免了頻繁地修改DOM樹(shù)結(jié)構(gòu),減少了回流的次數(shù)。

通過(guò)使用文檔片段進(jìn)行批量插入和刪除操作,我們可以優(yōu)化DOM操作,減少回流的次數(shù),提高性能和用戶體驗(yàn)。

字符串拼接:
假設(shè)我們有一個(gè)待完成任務(wù)列表,用戶可以通過(guò)輸入框添加新任務(wù)并點(diǎn)擊按鈕進(jìn)行保存。每當(dāng)用戶添加新任務(wù)時(shí),我們需要?jiǎng)討B(tài)地將新任務(wù)添加到DOM樹(shù)中的任務(wù)列表中。為了避免頻繁修改DOM樹(shù)結(jié)構(gòu)導(dǎo)致的性能問(wèn)題,我們可以使用字符串拼接的方式生成HTML代碼,并將生成的HTML一次性地插入DOM樹(shù)。

<!DOCTYPE html>
<html>
<head>
  <title>待完成任務(wù)列表</title>
</head>
<body>
  <div id="taskList"></div>
  <input type="text" id="taskInput">
  <button id="addButton">Add Task</button>

  <script>
    var taskList = document.getElementById('taskList');
    var taskInput = document.getElementById('taskInput');
    var addButton = document.getElementById('addButton');
    var tasks = [];

    // 監(jiān)聽(tīng)按鈕點(diǎn)擊事件
    addButton.addEventListener('click', function() {
      var taskName = taskInput.value;
      if (taskName) {
        tasks.push(taskName);

        // 使用字符串拼接生成HTML代碼
        var html = '';
        for (var i = 0; i < tasks.length; i++) {
          html += '<div>' + tasks[i] + '</div>';
        }

        // 批量插入任務(wù)列表
        var fragment = document.createElement('div');
        fragment.innerHTML = html;
        taskList.appendChild(fragment);

        // 清空輸入框
        taskInput.value = '';
      }
    });
  </script>
</body>
</html>

在上述案例中,當(dāng)用戶點(diǎn)擊添加按鈕時(shí),我們通過(guò)使用字符串拼接的方式生成HTML代碼,并將生成的HTML代碼一次性地插入DOM樹(shù)中的任務(wù)列表中。通過(guò)一次性插入,可以避免頻繁修改DOM樹(shù)結(jié)構(gòu),從而減少回流的次數(shù),提升頁(yè)面性能。

9. 使用debounce或throttle來(lái)降低頻繁調(diào)用回流的次數(shù),例如使用lodash庫(kù)中的debounce和throttle方法。

防抖(debounce)和節(jié)流(throttle)是前端開(kāi)發(fā)中常用的優(yōu)化方法,用于限制某些頻繁觸發(fā)的事件的執(zhí)行次數(shù),提高網(wǎng)頁(yè)性能和用戶體驗(yàn)。

防抖:在某個(gè)事件觸發(fā)后,在規(guī)定的時(shí)間內(nèi),如果事件再次被觸發(fā),將重新計(jì)時(shí)。只有當(dāng)在規(guī)定時(shí)間內(nèi)事件沒(méi)有再次觸發(fā)時(shí),才會(huì)執(zhí)行事件處理函數(shù)。通常用于針對(duì)于用戶頻繁觸發(fā)的事件進(jìn)行優(yōu)化,如輸入框中實(shí)時(shí)搜索。防抖可以防止在用戶連續(xù)輸入時(shí)頻繁發(fā)送請(qǐng)求,而是等用戶停止輸入后再進(jìn)行請(qǐng)求,減少請(qǐng)求次數(shù)和服務(wù)器壓力。

節(jié)流:在某個(gè)事件觸發(fā)后,在規(guī)定的時(shí)間內(nèi),無(wú)論事件觸發(fā)多少次,事件處理函數(shù)只會(huì)執(zhí)行一次。通常用于限制某些高頻率觸發(fā)的事件,如頁(yè)面滾動(dòng)事件。節(jié)流可以限制事件處理函數(shù)的執(zhí)行頻率,避免頻繁觸發(fā)導(dǎo)致性能問(wèn)題,并且保證了頁(yè)面響應(yīng)的流暢性。

兩者的區(qū)別在于執(zhí)行的時(shí)機(jī)不同。防抖是在事件觸發(fā)后等待一段時(shí)間后再執(zhí)行事件處理函數(shù),而節(jié)流是在事件觸發(fā)后立即執(zhí)行事件處理函數(shù),并且在規(guī)定時(shí)間內(nèi)只執(zhí)行一次。防抖適用于用戶頻繁觸發(fā)的事件,而節(jié)流適用于高頻率觸發(fā)的事件。

以下是使用 JavaScript 實(shí)現(xiàn)防抖函數(shù)和節(jié)流函數(shù)的示例代碼:

防抖函數(shù)的實(shí)現(xiàn):

function debounce(func, delay) {
    let timerId;
  
    return function() {
        clearTimeout(timerId);
        timerId = setTimeout(func, delay);
    }
}

// 使用示例
function handleDebounce() {
    console.log('Debounced function is called');
}

const debouncedFunc = debounce(handleDebounce, 300);
debouncedFunc(); // 只有在 300ms 內(nèi)沒(méi)有再次調(diào)用時(shí)才會(huì)執(zhí)行 handleDebounce 函數(shù)

節(jié)流函數(shù)的實(shí)現(xiàn):

function throttle(func, delay) {
    let timerId;
    let lastExecTime = 0;
  
    return function() {
        const currentTime = Date.now();
        const elapsed = currentTime - lastExecTime;
        const context = this;
        const args = arguments;
        
        if (elapsed < delay) {
            clearTimeout(timerId);
            timerId = setTimeout(function() {
                lastExecTime = currentTime;
                func.apply(context, args);
            }, delay - elapsed);
        } else {
            lastExecTime = currentTime;
            func.apply(context, args);
        }
    }
}

// 使用示例
function handleThrottle() {
    console.log('Throttled function is called');
}

const throttledFunc = throttle(handleThrottle, 300);
throttledFunc(); // 間隔小于 300ms 時(shí)不執(zhí)行 handleThrottle 函數(shù),超過(guò) 300ms 才執(zhí)行

debounce和throttle是兩種用于限制函數(shù)執(zhí)行頻率的方法,可以幫助我們避免頻繁調(diào)用導(dǎo)致的回流問(wèn)題。下面以一個(gè)實(shí)際案例來(lái)說(shuō)明如何使用debounce和throttle來(lái)減少回流的次數(shù)。

假設(shè)我們有一個(gè)搜索框,當(dāng)用戶在搜索框中輸入時(shí),我們希望在用戶停止輸入后的500毫秒內(nèi)執(zhí)行搜索操作,以減少不必要的網(wǎng)絡(luò)請(qǐng)求。

首先,我們需要引入lodash庫(kù),它提供了debounce和throttle方法。

import { debounce, throttle } from 'lodash';

然后,我們需要?jiǎng)?chuàng)建一個(gè)搜索函數(shù)。

function search(query) {
  // 發(fā)起搜索請(qǐng)求的邏輯
  console.log('搜索關(guān)鍵詞:', query);
}

接下來(lái),我們可以使用debounce方法來(lái)創(chuàng)建一個(gè)在用戶停止輸入500毫秒后執(zhí)行search函數(shù)的新函數(shù)。

const debouncedSearch = debounce(search, 500);

最后,我們需要監(jiān)聽(tīng)用戶的輸入事件,并調(diào)用debouncedSearch函數(shù)。

const inputElement = document.querySelector('input');

inputElement.addEventListener('input', (event) => {
  const query = event.target.value;
  debouncedSearch(query);
});

這樣,當(dāng)用戶輸入時(shí),debouncedSearch函數(shù)會(huì)在500毫秒內(nèi)只被調(diào)用一次。如果用戶在500毫秒內(nèi)持續(xù)輸入,debouncedSearch函數(shù)不會(huì)被調(diào)用,避免了頻繁的網(wǎng)絡(luò)請(qǐng)求。

類似地,我們也可以使用throttle方法來(lái)限制函數(shù)的執(zhí)行頻率。throttle方法與debounce方法的區(qū)別在于,throttle會(huì)在一定時(shí)間間隔內(nèi)多次執(zhí)行函數(shù),而debounce只會(huì)在指定時(shí)間內(nèi)的最后一次調(diào)用生效。根據(jù)具體情況,選擇合適的方法可以幫助我們降低回流的次數(shù)。

10.使用requestAnimationFrame替代setInterval可以提升瀏覽器的性能。

使用requestAnimationFrame替代setInterval制作勻速動(dòng)畫(huà)
上面這篇文章記錄了如何使用requestAnimationFrame替代setInterval的一個(gè)實(shí)際案例,感興趣的可以看看。

使用setInterval來(lái)制作動(dòng)畫(huà)時(shí),會(huì)有一個(gè)固定的時(shí)間間隔來(lái)執(zhí)行代碼,但是這個(gè)時(shí)間間隔是不精確的,因?yàn)?code>JavaScript是單線程的,執(zhí)行代碼時(shí)可能會(huì)受到其他任務(wù)和事件的影響。這會(huì)導(dǎo)致動(dòng)畫(huà)的幀率不穩(wěn)定,甚至出現(xiàn)卡頓的情況。

而使用requestAnimationFrame方法,瀏覽器會(huì)根據(jù)自身的刷新率來(lái)決定回調(diào)函數(shù)的執(zhí)行時(shí)機(jī),這樣可以保證動(dòng)畫(huà)的幀率穩(wěn)定且流暢。同時(shí),requestAnimationFrame方法還會(huì)在瀏覽器的重新繪制之前執(zhí)行,這樣可以更好地將動(dòng)畫(huà)與瀏覽器的繪制過(guò)程同步,避免不必要的重繪。

另外,requestAnimationFrame方法還可以在動(dòng)畫(huà)不可見(jiàn)時(shí)自動(dòng)暫停,節(jié)省了不必要的計(jì)算資源。

總之,使用requestAnimationFrame替代setInterval可以提升瀏覽器的性能,實(shí)現(xiàn)更加流暢和高效的動(dòng)畫(huà)效果。

11. 盡量減少頁(yè)面中元素的數(shù)量和復(fù)雜度,可以對(duì)不需要展示的元素進(jìn)行隱藏或延遲加載,減少回流的發(fā)生。

通過(guò)遵循上述優(yōu)化策略,可以有效地減少或者優(yōu)化回流現(xiàn)象,提高前端開(kāi)發(fā)web應(yīng)用的性能。

總結(jié)

在這篇博客文章中,我們深入探討了前端性能優(yōu)化中的瀏覽器渲染優(yōu)化。我們了解到,在構(gòu)建高性能的前端應(yīng)用程序時(shí),優(yōu)化瀏覽器渲染過(guò)程是至關(guān)重要的。通過(guò)理解瀏覽器的渲染流程,并采取一些有效的優(yōu)化策略,我們可以顯著提高應(yīng)用程序的性能和用戶體驗(yàn)。

我們?cè)敿?xì)介紹了如何最小化渲染層級(jí)并減少重排重繪操作。通過(guò)使用合適的HTML和CSS結(jié)構(gòu),以及避免頻繁的DOM操作,我們可以減少瀏覽器重新計(jì)算布局和重新繪制的次數(shù),從而提高渲染效率。

總的來(lái)說(shuō),優(yōu)化瀏覽器渲染性能是提高前端應(yīng)用程序性能的關(guān)鍵之一。通過(guò)了解瀏覽器的渲染過(guò)程,并采取一些有效的優(yōu)化策略,我們可以使我們的應(yīng)用程序更加高效、響應(yīng)更快,從而提升用戶的滿意度和體驗(yàn)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-672079.html

到了這里,關(guān)于前端性能優(yōu)化之瀏覽器渲染優(yōu)化的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 前端面試:【瀏覽器與渲染引擎】工作原理與渲染流程

    嗨,親愛(ài)的讀者!你是否曾經(jīng)好奇過(guò)當(dāng)你在瀏覽器中輸入U(xiǎn)RL并按下回車時(shí),網(wǎng)頁(yè)是如何顯示在你的屏幕上的?這背后涉及了復(fù)雜的瀏覽器工作原理和渲染流程。本文將帶你深入了解瀏覽器如何工作以及網(wǎng)頁(yè)如何被渲染出來(lái)。 1. 瀏覽器的工作原理: 當(dāng)你輸入U(xiǎn)RL并按下回車時(shí),

    2024年02月11日
    瀏覽(100)
  • 前端秘法進(jìn)階篇----這還是我們熟悉的瀏覽器嗎?(瀏覽器的渲染原理)

    前端秘法進(jìn)階篇----這還是我們熟悉的瀏覽器嗎?(瀏覽器的渲染原理)

    目錄 一.瀏覽器渲染原理 二.渲染時(shí)間點(diǎn) 三.渲染流水線 1.解析html(Parse HTML) 1.1解析成DOM樹(shù)(document object model) 1.2解析成CSSOM樹(shù)(css?object model) 2.樣式計(jì)算(Recalculate Style) 3.布局(Layout) 4.分層(Layer) 5. 繪制(Paint) 6.分塊(Tiling) 7. 光柵化(Raster) 8. 畫(huà)(Draw) 四.附加面試題 1.什么是 reflow? 2.什

    2024年02月21日
    瀏覽(20)
  • 移動(dòng)端瀏覽器性能優(yōu)化探索

    移動(dòng)端瀏覽器性能優(yōu)化探索

    在移動(dòng)端的頁(yè)面開(kāi)發(fā)過(guò)程中,我們經(jīng)常提及頁(yè)面性能優(yōu)化、消除頁(yè)面卡頓的話題,如何·確定優(yōu)化策略,我們首先應(yīng)當(dāng)對(duì)頁(yè)面卡頓的行為有所認(rèn)知。 前言 ? 頁(yè)面的卡頓現(xiàn)象可以比較明確的分為三個(gè)類型,分別是 “畫(huà)面撕裂” 、“丟幀不流暢”、“長(zhǎng)時(shí)間未響應(yīng)”。 “畫(huà)面

    2024年02月06日
    瀏覽(49)
  • 前端面試的話術(shù)集錦第 7 篇:高頻考點(diǎn)(瀏覽器渲染原理 & 安全防范)

    這是記錄 前端面試的話術(shù)集錦第七篇博文——高頻考點(diǎn)(瀏覽器渲染原理 安全防范) ,我會(huì)不斷更新該博文。??? 注意:該章節(jié)都是?個(gè)?試題。 1.1.1 瀏覽器接收到HTML?件并轉(zhuǎn)換為DOM樹(shù) 當(dāng)我們打開(kāi)?個(gè)??時(shí),瀏覽器都會(huì)去請(qǐng)求對(duì)應(yīng)的 HTML ?件。雖然平時(shí)我們寫(xiě)代碼時(shí)

    2024年02月03日
    瀏覽(25)
  • 前端面試:【瀏覽器與渲染引擎】Web APIs - DOM、XHR、Fetch、Canvas

    嗨,親愛(ài)的讀者!當(dāng)我們?cè)跒g覽器中瀏覽網(wǎng)頁(yè)時(shí),我們常常會(huì)與各種Web API打交道。這些API允許我們與網(wǎng)頁(yè)內(nèi)容、服務(wù)器資源和圖形進(jìn)行交互。本文將深入探討一些常見(jiàn)的Web API,包括DOM、XHR、Fetch和Canvas,以幫助你了解它們的用途和如何使用它們。 1. DOM(文檔對(duì)象模型): 用

    2024年02月11日
    瀏覽(21)
  • Java教程:如何讀取服務(wù)器文件并推送到前端并下載,圖片格式以瀏覽器渲染模式

    Java教程:如何讀取服務(wù)器文件并推送到前端并下載,圖片格式以瀏覽器渲染模式

    ----在我們做文件上傳時(shí),通常會(huì)保存文件的相對(duì)路徑在數(shù)據(jù)庫(kù)中,然后返回前端http訪問(wèn)路徑,來(lái)對(duì)文件進(jìn)行下載或圖片預(yù)覽功能,但是有時(shí)候我們并不想直接返回文件訪問(wèn)地址給前端,這就用到了Java當(dāng)中的文件輸入輸出流,將文件以流的方式響應(yīng)給瀏覽器,并渲染出圖片或

    2024年02月03日
    瀏覽(28)
  • 瀏覽器渲染機(jī)制

    瀏覽器渲染機(jī)制

    學(xué)習(xí)渡一課程、參考 必須明白的瀏覽器渲染機(jī)制 - 掘金 HTML解析 布局 分層 繪制 分塊 光柵化 畫(huà) 解析html會(huì)生成一個(gè) dom樹(shù)和cssom樹(shù) ? document.styleSheets? 可以看到cssom樹(shù) ? ? 渲染阻塞 在渲染的過(guò)程中,遇到一個(gè)script標(biāo)記時(shí),就會(huì)停止渲染,去請(qǐng)求腳本文件并執(zhí)行腳本文件,因?yàn)?/p>

    2024年02月11日
    瀏覽(48)
  • 瀏覽器渲染原理

    瀏覽器渲染原理

    當(dāng)你在地址欄輸入內(nèi)容回車后,瀏覽器進(jìn)程中的UI線程會(huì)捕捉輸入內(nèi)容,如果訪問(wèn)的是網(wǎng)址,會(huì)啟動(dòng)一個(gè)網(wǎng)絡(luò)線程來(lái)進(jìn)行DNS解析;后面連接服務(wù)器獲取數(shù)據(jù);如果輸入的不是網(wǎng)址而是,就會(huì)使用默認(rèn)配置的搜索引擎來(lái)進(jìn)行查詢 網(wǎng)絡(luò)進(jìn)程獲取到數(shù)據(jù)后會(huì)使用safeBrowsing檢查

    2024年02月07日
    瀏覽(67)
  • 瀏覽器渲染流程

    瀏覽器渲染流程

    解析HTML,生成DOM樹(shù),解析CSS,生成CSSOM樹(shù) 將DOM樹(shù)和CSSOM樹(shù)結(jié)合,生成渲染樹(shù)(Render Tree) Layout(回流):根據(jù)生成的渲染樹(shù),進(jìn)行回流(Layout),得到節(jié)點(diǎn)的幾何信息(位置,大?。?Painting(重繪):根據(jù)渲染樹(shù)以及回流得到的幾何信息,得到節(jié)點(diǎn)的絕對(duì)像素 Display:將像素發(fā)送給GPU,展示在

    2024年02月09日
    瀏覽(19)
  • 【autodesk】瀏覽器中渲染rvt模型

    【autodesk】瀏覽器中渲染rvt模型

    Forge是什么 為什么能夠渲染出來(lái)rvt模型 Forge是由Autodesk開(kāi)發(fā)的一套云端開(kāi)發(fā)平臺(tái)和工具集。 在Forge平臺(tái)中,有一個(gè)名為\\\"Model Derivative\\\"的服務(wù),它可以將包括RVT(Revit)在內(nèi)的多種BIM(Building Information Modeling)文件格式轉(zhuǎn)換為可在Web上瀏覽和渲染的格式。 具體來(lái)說(shuō),\\\"Model Derivat

    2024年02月09日
    瀏覽(19)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包