解鎖JavaScript性能優化:從理論到實戰

文章目錄

  • 前言
  • 一、常見性能瓶頸剖析
  • 二、實戰案例與優化方案
    • (一)DOM 操作優化案例?
    • (二)事件綁定優化案例?
    • (三)循環與遞歸優化案例?
    • (四)內存管理優化案例?
  • 三、性能優化工具介紹
  • 總結


前言

性能優化的重要性
在這里插入圖片描述
在當今數字化時代,Web 應用已成為人們生活和工作中不可或缺的一部分。而 JavaScript 作為 Web 開發的核心語言,其性能優劣直接決定了用戶體驗的好壞。想象一下,當你滿心期待地打開一個網頁,卻遭遇長時間的加載等待,或者在操作過程中頁面頻繁卡頓,這種糟糕的體驗無疑會讓你對該應用失去耐心和好感。?
對于企業來說,性能問題可能導致用戶流失、業務受損。根據相關研究表明,網頁加載時間每增加一秒,用戶流失率可能會上升 7% ,轉化率也會大幅下降。而在搜索引擎排名方面,性能出色的網站往往更受青睞,能獲得更高的權重和曝光機會。此外,良好的性能優化還能降低服務器負載,節約運營成本。?
由此可見,JavaScript 性能優化絕非可有可無,而是關乎應用成敗的關鍵因素。接下來,本文將通過一系列真實的實戰案例,深入剖析性能瓶頸產生的原因,并詳細介紹針對性的優化方法,助你掌握提升 JavaScript 性能的核心技巧 。


一、常見性能瓶頸剖析

(一)重繪與重排?
在網頁渲染過程中,重繪(Repaint)和重排(Reflow,也稱為回流)是兩個重要概念,它們直接影響著 JavaScript 的性能。當元素的樣式改變但不影響其在文檔流中的位置和幾何形狀時,比如改變元素的顏色、背景、邊框等,瀏覽器會進行重繪,這個過程只需要重新繪制受影響的元素,無需重新計算布局 ,代價相對較小。然而,當元素的尺寸、布局或位置發生改變,如改變元素的寬度、高度、添加 / 刪除元素、改變窗口大小等操作時,瀏覽器需要重新計算文檔中元素的位置和大小,此為重排。重排是一個代價較高的操作,因為它不僅會影響當前元素及其子元素,甚至可能影響后續兄弟元素和祖先元素,瀏覽器需要重新計算布局,并重新繪制受影響的部分。?
頻繁的 DOM 操作是引發重繪和重排的常見原因。以一個簡單的列表為例,如果通過循環逐個修改列表項的樣式,每一次修改都可能觸發重排和重繪。如下面的代碼:

const listItems = document.querySelectorAll('li');
for (let i = 0; i < listItems.length; i++) {listItems[i].style.color = 'red';listItems[i].style.marginLeft = '10px';
}

在這個例子中,每次循環都對列表項的樣式進行了兩次修改,這會導致瀏覽器頻繁地進行重排和重繪,嚴重影響性能。?
(二)主線程阻塞?
JavaScript 是單線程語言,這意味著它在同一時間只能執行一個任務。在瀏覽器環境中,JavaScript 的執行與頁面渲染、用戶交互等都在主線程中進行。當主線程被一些復雜的計算任務或者大量的 DOM 操作占據時,就會導致主線程阻塞。例如,進行復雜的數學運算、解析龐大的 JSON 數據、頻繁地操作 DOM 元素等。?
假設我們有一個計算斐波那契數列的函數:

function fibonacci(n) {if (n <= 1) return n;return fibonacci(n - 1) + fibonacci(n - 2);
}// 進行大量的斐波那契數列計算,阻塞主線程
for (let i = 0; i < 40; i++) {fibonacci(i);
}

在上述代碼中,fibonacci函數是一個遞歸函數,計算過程非常耗時。當在循環中多次調用該函數時,會使主線程長時間處于忙碌狀態,導致頁面無法及時響應用戶的操作,如點擊按鈕、滾動頁面等,給用戶帶來極差的體驗。?
(三)內存泄漏?
內存泄漏指的是程序中已分配的內存由于某種原因無法被釋放,導致內存占用不斷增加,最終可能影響程序的性能甚至導致程序崩潰。在 JavaScript 中,常見的內存泄漏場景有閉包濫用、未移除事件監聽器等。?
當閉包被不當使用時,就可能引發內存泄漏。例如:

function outerFunction() {const largeData = new Array(1000000);  // 占用大量內存的數據return function innerFunction() {console.log(largeData.length);};
}const closure = outerFunction();  // 這里形成閉包,即使outerFunction執行完畢,largeData也無法被回收

在這個例子中,outerFunction返回的innerFunction形成了閉包,它引用了outerFunction中的largeData。即使outerFunction執行完畢,largeData仍然被innerFunction引用,從而無法被垃圾回收機制回收,造成內存泄漏。?
另外,在為 DOM 元素添加事件監聽器后,如果在元素被移除時沒有手動移除對應的事件監聽器,也會導致內存泄漏。例如:

const button = document.createElement('button');
button.addEventListener('click', function clickHandler() {console.log('Button clicked');
});
document.body.appendChild(button);// 后續移除按鈕,但未移除事件監聽器
document.body.removeChild(button);

在上述代碼中,按鈕被從頁面移除后,其點擊事件監聽器仍然存在于內存中,并且持有對按鈕 DOM 元素的引用,導致按鈕及其相關資源無法被回收,造成內存泄漏。

二、實戰案例與優化方案

(一)DOM 操作優化案例?

在 Web 開發中,動態渲染長列表是一個常見的需求。但如果處理不當,就會引發嚴重的性能問題。假設我們要在頁面上渲染一個包含 10000 條數據的列表,以下是一段可能的低效代碼:

const data = Array.from({ length: 10000 }, (_, i) => `Item ${i}`);
const list = document.getElementById('list');
data.forEach(item => {list.innerHTML += `<li>${item}</li>`;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95779.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95779.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95779.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

結構化記憶、知識圖譜與動態遺忘機制在醫療AI中的應用探析(上)

往期相關內容推薦: 基于Python的多元醫療知識圖譜構建與應用研究(上)

XSS攻擊:從原理入門到實戰精通詳解

一、XSS攻擊基礎概念1.1 什么是XSS攻擊 XSS&#xff08;Cross-Site Scripting&#xff0c;跨站腳本攻擊&#xff09;是一種將惡意腳本注入到可信網站中的攻擊手段。當用戶訪問被注入惡意代碼的頁面時&#xff0c;瀏覽器會執行這些代碼&#xff0c;導致&#xff1a;用戶會話被劫…

Leetcode 14 java

今天復習一下以前做過的題目&#xff0c;感覺是忘光了。 160. 相交鏈表 給你兩個單鏈表的頭節點 headA 和 headB &#xff0c;請你找出并返回兩個單鏈表相交的起始節點。如果兩個鏈表不存在相交節點&#xff0c;返回 null 。 圖示兩個鏈表在節點 c1 開始相交&#xff1a; 題目數…

用 FreeMarker 動態構造 SQL 實現數據透視分析

在 ERP、BI 等系統中&#xff0c;數據透視分析&#xff08;Pivot Analysis&#xff09;是非常常見的需求&#xff1a;用戶希望按任意維度&#xff08;如門店、時間、商品分類等&#xff09;進行分組統計&#xff0c;同時選擇不同的指標&#xff08;如 GMV、訂單數、客單價等&am…

13.深度學習——Minst手寫數字識別

第一部分——起手式 import torch from torchvision import datasets, transforms import torch.nn as nn import torch.nn.functional as F import torch.optim as optimuse_cuda torch.cuda.is_available()if use_cuda:device torch.device("cuda") else: device…

【JAVA高級】實現word轉pdf 實現,源碼概述。深坑總結

之前的需求做好后,需求,客戶突發奇想。要將生成的word轉為pdf! 因為不想讓下載文檔的人改動文檔。 【JAVA】實現word添加標簽實現系統自動填入字段-CSDN博客 事實上這個需求難度較高,并不是直接轉換就行的 word文檔當中的很多東西都需要處理 public static byte[] gener…

數據驅動測試提升自動化效率

測試工程師老王盯著滿屏重復代碼嘆氣&#xff1a;“改個搜索條件要重寫20個腳本&#xff0c;這班加到啥時候是個頭&#xff1f;” 隔壁組的小李探過頭&#xff1a;“試試數據驅動唄&#xff0c;一套腳本吃遍所有數據&#xff0c;我們組上周測了300個組合都沒加班&#xff01;”…

模板引用(Template Refs)全解析2

三、v-for 中的模板引用 當在 v-for 中使用模板引用時,引用的 value 會自動變為一個數組,包含列表中所有元素/組件的引用(需 Vue 3.5+ 版本,舊版需手動處理且順序不保證)。 1. 基本用法(Vue 3.5+) <script setup> import { ref, useTemplateRef, onMounted } f…

【Linux系統】進程間通信:System V IPC——共享內存

前文中我們介紹了管道——匿名管道和命名管道來實現進程間通信&#xff0c;在介紹怎么進行通信時&#xff0c;我們有提到過不止管道的方式進行通信&#xff0c;還有System V IPC&#xff0c;今天這篇文章我們就來學習一下System V IPC中的共享內存1. 為何引入共享內存&#xff…

[優選算法專題二滑動窗口——最大連續1的個數 III]

題目鏈接 最大連續1的個數 III 題目描述 題目解析 問題本質 輸入&#xff1a;二進制數組nums&#xff08;只包含 0 和 1&#xff09;和整數k操作&#xff1a;最多可以將k個 0 翻轉成 1目標&#xff1a;找到翻轉后能得到的最長連續 1 的子數組長度 這個問題的核心是要找到一…

C#單元測試(xUnit + Moq + coverlet.collector)

C#單元測試 xUnit Moq coverlet.collector 1.添加庫 MlyMathLib 2.編寫庫函數內容 using System;namespace MlyMathLib {public interface IUserRepo{string GetName(int id);}public class UserService{private readonly IUserRepo _repo;public UserService(IUserRepo repo…

【數據庫】Oracle學習筆記整理之五:ORACLE體系結構 - 參數文件與控制文件(Parameter Files Control Files)

Oracle體系結構 - 參數文件與控制文件&#xff08;Parameter Files & Control Files&#xff09; 參數文件與控制文件是Oracle數據庫的“雙核基石”&#xff1a;參數文件是實例的“啟動配置中心”&#xff0c;定義運行環境與規則&#xff1b;控制文件是數據庫的“物理元數據…

GDB典型開發場景深度解析

GDB典型開發場景深度解析 以下是開發過程中最常見的GDB使用場景&#xff0c;結合具體實例和調試技巧&#xff0c;幫助開發者高效解決實際問題&#xff1a;一、崩潰分析&#xff08;Core Dump調試&#xff09; 場景&#xff1a;程序突然崩潰&#xff0c;生成了core文件 # 啟動調…

存儲、硬盤、文件系統、 IO相關常識總結

目錄 &#xff08;一&#xff09;存儲 &#xff08;1&#xff09;定義 &#xff08;2&#xff09;分類 &#xff08;二&#xff09;硬盤 &#xff08;1&#xff09;容量&#xff08;最主要的參數&#xff09; &#xff08;2&#xff09;轉速 &#xff08;3&#xff09;訪…

docker安裝mongodb及java連接實戰

1.docker部署mongodb docker run --name mongodb -d -p 27017:27017 -v /data/mongodbdata:/data/db -e MONGO_INITDB_ROOT_USERNAMEtestmongo -e MONGO_INITDB_ROOT_PASSWORDtest123456 mongodb:4.0.112.項目實戰 <dependencies><dependency><groupId>org.m…

Java設計模式之《工廠模式》

目錄 1、介紹 1.1、定義 1.2、優缺點 1.3、使用場景 2、實現 2.1、簡單工廠模式 2.2、工廠方法模式 2.3、抽象工廠模式 3、小結 前言 在面向對象編程中&#xff0c;創建對象實例最常用的方式就是通過 new 操作符構造一個對象實例&#xff0c;但在某些情況下&#xff0…

【異步】js中異步的實現方式 async await /Promise / Generator

JS的異步相關知識 js里面一共有以下異步的解決方案 傳統的回調 省略 。。。。 生成器 Generator 函數是 ES6 提供的一種異步編程解決方案, 語法上&#xff0c;首先可以把它理解成&#xff0c;Generator 函數是一個狀態機&#xff0c;封裝了多個內部狀態。執行 Generator 函數…

JVM字節碼文件結構

Class文件結構class文件是二進制文件&#xff0c;這里要介紹的是這個二級制文件的結構。思考&#xff1a;一個java文件編譯成class文件&#xff0c;如果要描述一個java文件&#xff0c;需要哪些信息呢&#xff1f;基本信息&#xff1a;類名、父類、實現哪些接口、方法個數、每個…

11.web api 2

5. 操作元素屬性 5.1操作元素常用屬性 &#xff1a;通過 JS 設置/修改標簽元素屬性&#xff0c;比如通過 src更換 圖片最常見的屬性比如&#xff1a; href、title、src 等5.2 操作元素樣式屬性 &#xff1a;通過 JS 設置/修改標簽元素的樣式屬性。使用 className 有什么好處&a…

java中數組和list的區別是什么?

在Java中&#xff0c;數組&#xff08;Array&#xff09;和List&#xff08;通常指java.util.List接口的實現類&#xff0c;如ArrayList、LinkedList&#xff09;是兩種常用的容器&#xff0c;但它們在設計、功能和使用場景上有顯著區別。以下從核心特性、使用方式等方面詳細對…