Web 網頁性能及性能優化

来源:https://www.cnblogs.com/risheng/p/18231440
-Advertisement-
Play Games

Web 性能是 Web 開發的一個重要方面,側重於網頁載入速度以及對用戶輸入的響應速度 通過優化網站來改善性能,可以在為用戶提供更好的體驗 網頁性能既廣泛又非常深入 1. 為什麼性能這麼重要? 1. 性能關乎留住用戶 性能對於任何線上業務都至關重要 與載入速度緩慢、讓人感覺運行緩慢的網站相比,載入速... ...


Web 網頁性能及性能優化

一、Web 性能

Web 性能是 Web 開發的一個重要方面,側重於網頁載入速度以及對用戶輸入的響應速度

通過優化網站來改善性能,可以在為用戶提供更好的體驗

網頁性能既廣泛又非常深入

1. 為什麼性能這麼重要?

1. 性能關乎留住用戶

性能對於任何線上業務都至關重要

與載入速度緩慢、讓人感覺運行緩慢的網站相比,載入速度快並能及時響應用戶輸入的網站能更好地吸引並留住用戶

2. 性能能提高轉化次數

性能會對網站用戶是否會瀏覽應用產生重大影響

3. 性能關乎用戶體驗

隨著網頁開始載入,用戶會等待一段時間,等待內容顯示。在此之前,就談不上用戶體驗

快速連接會讓這種體驗一閃而過。而如果連接速度較慢,用戶就不得不等待

image

性能是打造良好用戶體驗的基本要素

當網站發送大量代碼時,瀏覽器必須使用用戶流量套餐中的兆位元組流量下載應用

尤其是移動設備的 CPU 性能和記憶體有限。這可能會導致糟糕的性能條件,而且考慮到人們瞭解人類的行為,用戶只能容忍網站上的不利條件長達很長的時間,然後才會放棄網站

2. 網頁核心指標

2.1. 指標類型:

  • 感知載入速度:網頁可以多快地載入網頁中的所有視覺元素並將其渲染到屏幕上

  • 載入響應速度:頁面載入和執行組件快速響應用戶互動所需的任何 JavaScript 代碼的速度

  • 運行時響應速度:網頁在載入後對用戶互動的響應速度

  • 視覺穩定性:頁面上的元素是否會以用戶意想不到的方式發生偏移,是否可能會幹擾用戶的互動?

  • 流暢性:過渡和動畫是否以一致的幀速率渲染,併在一種狀態之間流暢地流動?

2.2. 要衡量的指標:

  • FCP(First Contentful Paint):從網頁開始載入到網頁內容的任何部分呈現在屏幕上所用的時間

  • LCP(Largest Contentful Paint):從網頁開始載入到屏幕上呈現最大的文本塊或圖片元素所用的時間

  • INP(Interaction to Next Paint):與網頁進行的每次 tapclick 或鍵盤互動的延遲時間,並根據交互的數量選擇頁面中最差的交互延遲作為單個代表性值來描述頁面的總體響應性

  • TBT(Total Blocking Time):從 FCP 到可交互時間 (TTI) 之間的總時長

  • CLS(Cumulative Layout Shift):從頁面開始載入到其生命周期狀態更改為隱藏期間發生的所有意外佈局偏移的累計分數

  • TTFB(Time to First Byte):網路使用資源的第一個位元組響應用戶請求所花費的時間

  • FID(First Input Delay):用戶首次與網頁互動(即,點擊鏈接、點按按鈕或使用由 JavaScript 提供支持的自定義控制項)到瀏覽器實際能夠開始處理事件處理腳本以響應相應互動的時間

2.3. Web 頁面性能衡量指標-以用戶為中心的性能指標

Web 頁面性能衡量指標-以用戶為中心的性能指標

二、性能優化

1. HTML 頁面性能優化

每個網站都是從請求 HTML 文檔開始的,該請求對網站的載入速度有著重大影響

要想構建可快速載入的網站,第一步就是要及時從伺服器接收網頁 HTML 的響應

當在瀏覽器的地址欄中輸入網址時,瀏覽器會向伺服器發送 GET 請求進行檢索

網頁的第一個請求針對的是 HTML 資源,因此,確保 HTML 以最短延遲快速到達是關鍵性能目標

1.1. 儘量減少重定向

在請求資源時,伺服器可能會做出一個重定向響應,該重定向可以是永久重定向(301 Moved Permanently 響應)或臨時重定向(302 Found 響應)

重定向會降低網頁載入速度,因為它需要瀏覽器在新位置發出額外的 HTTP 請求來檢索資源。重定向有兩種類型:

  1. 完全發生在源站內的同源重定向。這些類型的重定向完全由項目控制,因為管理它們的邏輯完全位於的 Web 伺服器上
  2. 由其他源啟動的跨域重定向。這些類型的重定向通常無法控制

1.2. 緩存 HTML 響應

緩存 HTML 響應很困難,因為響應可能包含指向其他關鍵資源(例如 CSSJavaScript、圖片和其他資源類型)的鏈接。這些資源的文件名中可能包含唯一指紋,該指紋會根據文件的內容而變化

但是較短的緩存生命周期(而不是不緩存)具有諸多優勢:

  • 允許在 CDN 中緩存資源,減少從源伺服器傳送的請求數量

  • 在瀏覽器中傳送資源,從而重新驗證資源而不是再次下載此

  • 可以將緩存資源的適當時間設置為合適的分鐘數

緩存 HTML 的一種方法是使用 ETagLast-Modified 響應標頭

ETag(也稱為實體標記)標頭是一個標識符,用於唯一標識所請求資源,通常使用資源內容的哈希值:

ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

每當資源發生變化時,都必鬚生成新的 ETag 值。在後續請求中,瀏覽器會通過 If-None-Match 請求標頭髮送 ETag 值。如果伺服器上的 ETag 與瀏覽器發送的 ETag 匹配,伺服器會返回 304 Not Modified 響應,瀏覽器則會使用緩存中的資源。雖然這仍然會導致網路延遲,但 304 Not Modified 響應比整個 HTML 資源小得多

但是,重新驗證資源的新鮮度涉及的網路延遲也本身也是一個缺點,需自行決定以這種方式緩存 HTML 的額外工作是否值得,或者最好是謹慎操作,不必費心緩存 HTML 內容。

1.3. 測量伺服器響應時間

如果響應未緩存,則伺服器的響應時間在很大程度上取決於的托管服務提供商和後端應用堆棧

與動態網頁相比,提供動態生成的響應(例如從資料庫獲取數據)的網頁的 TTFB 可能更高,無需在後端投入大量計算時間即可立即提供

1.4. 壓縮

基於文本的響應(例如 HTMLJavaScriptCSSSVG 圖片)應進行壓縮,以減小通過網路傳輸時的大小,從而加快其下載速度。最常用的壓縮演算法是 gzipBrotliBrotligzip 提高了約 15% 到 20%。

  • 儘可能使用 Brotli,所有主流瀏覽器都支持 Brotli,但如果網站有大量用戶在舊版瀏覽器中使用,請確保將 gzip 用作後備選項,因為任何壓縮都比不進行壓縮要好。
  • 文件大小至關重要。非常小的資源(小於 1 KiB)壓縮得不太好,有時甚至根本壓縮不到。任何類型的數據壓縮的效果都取決於能夠使用壓縮演算法找到更多可壓縮數據位的大量數據。文件越大,壓縮效果就越好
  • 瞭解動態壓縮和靜態壓縮。動態壓縮和靜態壓縮是確定何時應壓縮資源的不同方法
    • 動態壓縮會在請求資源時壓縮資源,有時甚至在每次請求資源時壓縮資源。
    • 靜態壓縮消除了壓縮本身涉及的延遲時間,在使用動態壓縮的情況下,這可能會增加伺服器響應時間。JavaScriptCSSSVG 圖片等靜態資源應靜態壓縮,而 HTML 資源應動態壓縮。

1.5. CDN

CDN 是分散式伺服器網路,伺服器從源伺服器緩存資源,反過來再從物理上更靠近用戶的邊緣伺服器傳送資源。在距離用戶較近時,可以縮短往返時間 (RTT),而 HTTP/2HTTP/3、緩存和壓縮等優化技術則可以讓 CDN 更快地提供內容,而不是從源伺服器提取內容。在某些情況下,使用 CDN 可以顯著改善網站的 TTFB

2. 關鍵渲染路徑

關鍵渲染路徑是網頁性能中的一個概念。

關鍵渲染路徑是指網頁開始在瀏覽器中呈現之前所涉及的步驟。為了呈現網頁,瀏覽器需要 HTML 文檔本身以及呈現該文檔所需的所有關鍵資源。

2.1. 漸進式渲染

網路是自然分佈的。與客戶端和 APP 不同,瀏覽器不能依賴於擁有呈現頁面所需的所有資源的網站。因此,瀏覽器非常擅長漸進式呈現頁面。原生應用通常有一個安裝階段,然後是運行階段。然而,對於網頁和網路應用來說,這兩個階段之間的界限就不那麼明顯了。

2.2. 關鍵渲染路徑

瀏覽器需要知道它應該等待的最小資源數量,以避免呈現明顯不正常的體驗。

另一方面,瀏覽器也不應該等待超過必要的時間才向用戶顯示一些內容。瀏覽器在執行初始呈現之前所採取的步驟序列稱為關鍵渲染路徑。

呈現路徑涉及以下步驟:

  • 通過 HTML 構建文檔對象模型 (DOM)

  • 通過 CSS 構建 CSS 對象模型 (CSSOM)

  • 應用任何會更改 DOMCSSOMJavaScript

  • 通過 DOMCSSOM 構建渲染樹

  • 在頁面上執行樣式和佈局操作,看看哪些元素適合顯示

  • 在記憶體中繪製元素的像素

  • 如果有任何像素重疊,則合成像素

  • 以物理方式將所有生成的像素繪製到屏幕上

image

只有在完成所有這些步驟後,用戶才會在屏幕上看到內容

這一呈現過程會發生多次。初始渲染會調用此流程,但隨著更多會影響網頁渲染的資源可用,瀏覽器將會重新運行此流程(或許只是其中的一部分),以更新用戶看到的內容。關鍵渲染路徑側重於之前為初始渲染概述的流程,並依賴於執行初始渲染所需的關鍵資源

2.3. 關鍵渲染路徑上有哪些資源?

瀏覽器需要等待一些關鍵資源下載完畢,然後才能完成初始渲染。這些資源包括:

  • HTML 的一部分
  • <head> 元素中阻塞渲染的 CSS
  • <head> 元素中的阻塞渲染的 JavaScript

關鍵在於瀏覽器以流式方式處理 HTML。瀏覽器一旦獲取網頁 HTML 的任何部分,就會開始對其進行處理。然後,瀏覽器就可以(並且通常確實)決定先呈現網頁,然後再接收網頁的其餘部分 HTML

3. 優化資源載入

網頁載入時,其 HTML 中會引用許多資源,通過 CSS 提供網頁的外觀和佈局,並通過 JavaScript 提供互動性。

3.1. 渲染阻塞

CSS 是一種阻塞渲染的資源,因為它會阻止瀏覽器渲染任何內容,直至構建了 CSS 對象模型 (CSSOM)。瀏覽器會阻止呈現,以防止出現非樣式內容閃爍 (FOUC)

渲染阻塞未必是不可取的,但需要通過對 CSS 進行優化來最大限度地縮短其持續時間

3.2. 預載入掃描器

3.2.1. 什麼是預載入掃描程式?

預載入掃描程式的角色是推測性,也就是說,它會檢查原始標記,以便查找資源,以便在主要 HTML 解析器發現之前抓取相應資源

預載入掃描程式是一種瀏覽器優化,採用輔助 HTML 解析器的形式,可掃描原始 HTML 響應,以找出並推測性地提取資源,然後主 HTML 解析器才會發現這些資源

為了充分利用預載入掃描器,伺服器發送的 HTML 標記中應包含關鍵資源。預載入掃描器無法發現以下資源載入模式:

  • CSS 使用 background-image 屬性載入的圖片。這些圖片引用位於 CSS 中,預載入掃描器無法發現這些引用
  • 動態載入的腳本,採用 <script> 元素標記(使用 JavaScript 註入 DOM)或使用動態 import() 載入的模塊
  • 使用 JavaScript 在客戶端上呈現的 HTML
  • CSS @import 聲明

這些資源載入模式都是後來發現的資源,請儘可能避免,如果無法避免此類模式,可以使用 preload 提示來避免資源發現延遲

3.3. CSS

CSS 決定了網頁的呈現方式和佈局,CSS 是一種阻止呈現的資源,因此優化 CSS 可能會對整體網頁載入時間產生重大影響

3.3.1. 縮減大小

縮減 CSS 文件大小可縮減 CSS 資源的文件大小,從而縮短下載速度。這主要是通過從 CSS 源文件中移除內容(例如空格和其他不可見字元)並將結果輸出到新優化的文件來實現的:

/* Heading 1 */
h1 {
  font-size: 2em;
  color: #000000;
}

/* Heading 2 */
h2 {
  font-size: 1.5em;
  color: #000000;
}
/* Minified CSS: */
h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}

就最基本的形式而言,CSS 縮減是一種有效的優化,可以提高網站的 FCP,在某些情況下或許甚至是 LCP

3.3.2. 移除未使用的 CSS

在呈現任何內容之前,瀏覽器需要先下載並解析所有樣式表。完成解析所需的時間還包括當前網頁上未使用的樣式。如果使用的打包器將所有 CSS 資源合併到一個文件中,那麼的用戶下載的 CSS 可能會比呈現當前網頁所需的數量多

如需發現當前網頁未使用的 CSS,可以使用 Chrome 開發者工具中的 coverage

image

移除未使用的 CSS 會產生雙重效果:除了縮短下載時間之外,還可以優化渲染樹的構建,因為瀏覽器需要處理的 CSS 規則更少

3.3.3. 避免使用 CSS @import 聲明

CSS 中的 @import 聲明允許從樣式表中導入外部 CSS 資源

可以使用 <link rel="stylesheet"> 元素替換 @import

3.3.4. 內嵌關鍵 CSS

關鍵 CSS 是指渲染在初始視窗中可見的內容所需的樣式。初始視窗的概念有時稱為“首屏”。網頁上的其餘內容將保持未設置樣式,而其餘的 CSS 將非同步載入。

但其缺點是,內嵌大量 CSS 會導致初始 HTML 響應的位元組增多。由於 HTML 資源通常無法緩存很長時間(甚至根本無法緩存),因此對於可能在外部樣式表中使用同一 CSS 的後續網頁,系統不會緩存內聯的 CSS

需測試和衡量網頁的性能

3.4. JS

載入過多的 JavaScript 可能會導致網頁在網頁載入期間響應緩慢,甚至可能導致響應速度問題減慢互動速度

3.4.1. 阻止呈現的 JS

載入不帶 deferasync 屬性的 <script> 元素時,瀏覽器會阻止解析和呈現,直到腳本下載、解析並執行完畢。同樣,內聯腳本也會阻止解析器,直到解析和執行腳本。

3.4.2. async 與 defer

asyncdefer 允許載入外部腳本,而不會阻止 HTML 解析器,而具有 type="module" 的腳本(包括內嵌腳本)會自動延遲。不過,asyncdefer 之間存在一些差異

image

使用 async 載入的腳本會在下載後立即解析和執行
使用 defer 載入的腳本會在 HTML 文檔解析完成時執行,這與瀏覽器的 DOMContentLoaded 事件同時發生
async 腳本可能會不按順序執行
defer 腳本則會按照它們在標記中出現的順序執行

使用 type="module" 屬性載入的腳本會處於延遲狀態,而使用 JavaScript<script> 標記註入 DOM 中載入的腳本則像 async 腳本

3.4.3. 客戶端渲染

應避免使用 JavaScript 來呈現任何關鍵內容或網頁的 LCP 元素。這稱為客戶端渲染,是一種在單頁應用 (SPA) 中廣泛使用的技術

3.4.3.1. LCP 元素
  • <img> 元素(第一幀呈現時間用於 GIF 或動畫 PNG 等動畫內容)

  • <svg> 元素內的 <image> 元素

  • <video> 元素(系統會使用視頻的海報圖片載入時間或第一幀顯示時間,以較早者為準)

  • 一個元素,帶有使用 url() 函數(而不是 CSS 漸變)載入的背景圖片

  • 包含文本節點或其他內嵌級文本元素子元素的塊級元素

3.4.4. 縮減大小

CSS 類似,縮減 JavaScript 大小可縮減腳本資源的文件大小。 這可以加快下載速度,使瀏覽器能夠更快地繼續解析和編譯 JavaScript 的過程

縮減 JavaScript 的大小比縮減其他資源更進一步。縮減 JavaScript 的大小時,不僅會去除空格、製表符和註釋等內容,而且源 JavaScript 中的符號也會被縮短

// Unuglified JavaScript source code:
export function injectScript () {
  const scriptElement = document.createElement('script');
  scriptElement.src = '/js/scripts.js';
  scriptElement.type = 'module';

  document.body.appendChild(scriptElement);
}
// Uglified JavaScript production code:
export function injectScript(){const t=document.createElement("script");t.src="/js/scripts.js",t.type="module",document.body.appendChild(t)}

4. 通過資源提示協助瀏覽器

資源提示是 HTML 中提供的一系列功能,可以幫助瀏覽器儘早載入資源,甚至可以採用更高的資源優先順序來載入資源

資源提示可以告知瀏覽器如何載入資源並確定資源優先順序,從而幫助開發者進一步縮短網頁載入時間。初始資源提示(例如 preconnectdns-prefetch)是最先引入的資源提示。隨著時間的推移,preloadFetch Priority API 相繼提供了額外的功能

資源提示會指示瀏覽器提前執行某些操作,這些操作可以提高載入性能。資源提示可以執行操作,例如執行早期 DNS 查找、提前連接到伺服器,甚至在瀏覽器通常發現資源之前提取資源。

資源提示可以在 HTML 中指定(通常在 <head> 元素早期),也可以設置為 HTTP 標頭

4.1. preconnect

preconnect 提示用於與另一個來源(要從其中提取關鍵資源)建立連接

<link rel="preconnect" href="https://example.com">

使用 preconnect 即表示預計瀏覽器計劃在不久的將來連接到特定的跨源伺服器,並且瀏覽器應儘快打開該連接,最好是在等待 HTML 解析器或預載入掃描程式執行此操作之前打開

如果網頁上有大量跨源資源,請對當前網頁最至關重要的資源使用 preconnect

preconnect 的常見用例是 Google Fonts

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

crossorigin 屬性用於指示是否必須使用跨域資源共用 (CORS) 提取資源。使用 preconnect 提示時,如果從來源下載的資源使用 CORS(例如字體文件),則需要將 crossorigin 屬性添加到 preconnect 提示中

4.2. dns-prefetch

雖然儘早打開與跨源伺服器的連接可以顯著縮短初始網頁載入時間,但同時與多個跨源伺服器建立連接可能不合理或不可行。如果擔心可能過度使用了 preconnect,可以使用 dns-prefetch 提示來使用開銷大大降低的資源提示

dns-prefetch 不會與跨源伺服器建立連接,而只是提前為其執行 DNS 查找。在將功能變數名稱解析為其底層 IP 地址時,會發生 DNS 查詢

雖然在設備和網路層級設置 DNS 緩存層有助於使此過程從總體上加快,但仍然需要一些時間

<link rel="dns-prefetch" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="https://fonts.gstatic.com">

DNS 查找的費用相當低廉,並且由於費用相對較小,在某些情況下,它們可能比 preconnect 更適合

4.3. preload

preload 指令用於提前請求呈現網頁所需的資源

<link rel="preload" href="/lcp-image.jpg" as="image">

preload 指令應僅限於後期發現的關鍵資源

最常見的用例包括字體文件、通過 @import 聲明提取的 CSS 文件,或可能是 LCP 候選對象的 CSS background-image 資源

如果使用 preload 下載由 <img> 元素指定的圖片,該圖片會根據用戶視窗的不同而有所不同

preconnect 類似,如果要預載入 CORS 資源(例如字體),則 preload 指令也需要 crossorigin 屬性

如果未添加 crossorigin 屬性(或者為非 CORS 請求添加該屬性),則瀏覽器會下載兩次資源,浪費帶寬,本來可以本該花在其他資源上

<link rel="preload" href="/font.woff2" as="font" crossorigin>

如果 preload 指令的 <link> 元素中缺少 as 屬性,該指令中指定的資源會下載兩次

4.4. prefetch

prefetch 指令用於針對可能會用於未來導航的資源發起低優先順序請求

<link rel="prefetch" href="/next-page.css" as="style">

此指令基本上遵循與 preload 指令相同的格式,只有 <link> 元素的 rel 屬性使用 prefetch

preload 指令不同,prefetch 主要是推測性的

鑒於 prefetch 的推測性,使用它的這一潛在缺點是,如果用戶沒有轉到最終需要預提取資源的頁面,那麼用於提取資源的數據就可能不會被使用。

4.5. Fetch Priority API

可以通過其 fetchpriority 屬性使用 Fetch Priority API 來提高資源的優先順序。可以將該屬性與 <link><img><script> 元素一起使用。

<div class="gallery">
  <div class="poster">
    <img src="img/poster-1.jpg" fetchpriority="high">
  </div>
  <div class="thumbnails">
    <img src="img/thumbnail-2.jpg" fetchpriority="low">
    <img src="img/thumbnail-3.jpg" fetchpriority="low">
    <img src="img/thumbnail-4.jpg" fetchpriority="low">
  </div>
</div>
4.5.1. 值
  • high
  • low
  • auto
4.5.2. 相容

image

5. 圖片載入性能

圖片代表了當今許多網頁上傳輸的大部分數據

圖片通常是網路上最龐大且最普遍的資源,在大多數情況下,優化圖片意味著通過減少發送的位元組數來減少網路時間,但也可以通過傳送適合用戶設備大小的圖片,從而優化發送給用戶的位元組數

可以使用 <img><picture> 元素或 CSS background-image 屬性將圖片添加到網頁中

5.1. 圖片大小

使用圖片資源時,可以執行的第一項優化是以正確的尺寸顯示圖片

在不考慮其他變數的情況下,在 500 x 500 像素容器中顯示的圖片的最佳大小為 500 x 500 像素。例如,使用 1000 像素的方形圖片意味著圖片大小將根據需要翻倍

選擇合適的圖片大小涉及許多變數,這使得在任何情況下選擇適當的圖片大小的任務都非常複雜

5.1.1. srcset

<img> 元素支持 srcset 屬性,該屬性可讓指定瀏覽器可能會使用的可能圖片來源的列表

指定的每個圖片來源都必須包含圖片網址,以及寬度或像素密度描述符

<img
  alt="An image"
  width="500"
  height="500"
  src="/image-500.jpg"
  srcset="/image-500.jpg 1x, /image-1000.jpg 2x, /image-1500.jpg 3x"
>
5.1.2. sizes

藉助 sizes 屬性,可以指定一組來源尺寸,其中每個來源尺寸都由媒體條件和值組成

sizes 屬性用於描述圖片的預期顯示尺寸(以 CSS 像素為單位)

srcset 寬度描述符結合使用時,瀏覽器可以選擇哪種圖片來源最適合用戶的設備

<img
  alt="An image"
  width="500"
  height="500"
  src="/image-500.jpg"
  srcset="/image-500.jpg 500w, /image-1000.jpg 1000w, /image-1500.jpg 1500w"
  sizes="(min-width: 768px) 500px, 100vw"
>

如果沒有 sizes 屬性,srcset 寬度描述符將不起作用。同樣,如果省略 srcset 寬度描述符,sizes 屬性也不會執行任何操作

5.2. 文件格式

瀏覽器支持多種不同的圖片文件格式。與 PNGJPEG 相比,新型圖片格式(例如 WebPAVIF)可提供更好的壓縮效果,從而縮小圖片文件大小,從而縮短下載時間。通過以現代格式提供圖片,可以縮短資源的載入時間,從而降低 Largest Contentful Paint (LCP) 速度。

5.2.1. WebP

WebP 是一種受到廣泛支持的格式,適用於所有新型瀏覽器

WebP 的壓縮效果通常比 JPEGPNGGIF 更好,既能提供有損壓縮,也提供無損壓縮。即使在使用有損壓縮時,WebP 也支持 Alpha 通道透明度,而 JPEG 編解碼器沒有此功能

5.2.2. AVIF

AVIF 是一種較新的圖片格式,雖然沒有 WebP 那麼廣泛支持,但它的跨瀏覽器支持相當得心應

AVIF 同時支持有損壓縮和無損壓縮,並且在某些情況下,與 JPEG 相比,測試的節省幅度超過了 50%。AVIF 還提供廣色域 (WCG) 和高動態範圍 (HDR) 功能

5.3. 壓縮

涉及圖像時,有兩種壓縮類型:

  1. 有損壓縮
  2. 無損壓縮
5.3.1. 有損壓縮

有損壓縮的工作原理是通過量化降低圖片準確性,並且可能會使用色度子採樣捨棄其他顏色信息

有損壓縮在雜訊和顏色多樣的高密度圖像上最有效

有損壓縮可應用於 JPEGWebPAVIF 圖片

使用有損壓縮時,請務必確認壓縮的圖片是否符合的質量標準

5.3.2. 無損壓縮

無損壓縮可以通過在不丟失數據的情況下壓縮圖片來減小文件大小

無損壓縮根據與相鄰像素之間的差異來描述像素

無損壓縮適用於 GIFPNGWebPAVIF 圖片格式

壓縮時,沒有適用於所有情況的通用設置。建議的方法是嘗試使用不同的壓縮級別,直到在圖片質量和文件大小之間找到適當的折衷方案為止

5.4. Picture 元素

<picture> 元素可讓更靈活地指定多個候選圖片

<picture>
  <source type="image/avif" srcset="image.avif">
  <source type="image/webp" srcset="image.webp">
  <img
    alt="An image"
    width="500"
    height="500"
    src="/image.jpg"
  >
</picture>

當在 <picture> 元素中使用 <source> 元素時,可以添加對 AVIFWebP 圖片的支持,但如果瀏覽器不支持現代格式,則回退到更相容的舊圖片格式

<source> 元素還支持 mediasrcsetsizes 屬性。與前面的 <img> 示例類似,這些變數會向瀏覽器指示要在不同視窗上選擇哪個圖片

<picture>
  <source
    media="(min-resolution: 1.5x)"
    srcset="/image-1000.jpg 1000w, /image-1500.jpg 1500w"
    sizes="(min-width: 768px) 500px, 100vw"
  >
  <img
    alt="An image"
    width="500"
    height="500"
    src="/image-500.jpg"
  >
</picture>
視窗寬度(像素) 1 DPR 1.5 DPR 2 DPR 3 DPR
320 500.jpg 500.jpg 500.jpg 1000.jpg
480 500.jpg 500.jpg 1000.jpg 1500.jpg
560 500.jpg 1000.jpg 1000.jpg 1500.jpg
1024 500.jpg 1000.jpg 1000.jpg 1500.jpg
1920 500.jpg 1000.jpg 1000.jpg 1500.jpg
<picture>
  <source
    media="(min-width: 560px) and (min-resolution: 1.5x)"
    srcset="/image-1000.jpg 1000w, /image-1500.jpg 1500w"
    sizes="(min-width: 768px) 500px, 100vw"
  >
  <source
    media="(max-width: 560px) and (min-resolution: 1.5x)"
    srcset="/image-1000-sm.jpg 1000w, /image-1500-sm.jpg 1500w"
    sizes="(min-width: 768px) 500px, 100vw"
  >
  <img
    alt="An image"
    width="500"
    height="500"
    src="/image-500.jpg"
  >
</picture>
視窗寬度(像素) 1 DPR 1.5 DPR 2 DPR 3 DPR
320 500.jpg 500.jpg 500.jpg 1000-sm.jpg
480 500.jpg 500.jpg 1000-sm.jpg 1500-sm.jpg
560 500.jpg 1000-sm.jpg 1000-sm.jpg 1500-sm.jpg
1024 500.jpg 1000.jpg 1000.jpg 1500.jpg
1920 500.jpg 1000.jpg 1000.jpg 1500.jpg

5.5. 延遲載入

可以使用 loading 屬性告知瀏覽器在圖片顯示在視窗中時延遲載入圖片

讓瀏覽器可以優先使用渲染視窗中已有的關鍵內容所需的資源

  • eager:預設行為, eager 告訴瀏覽器當處理 <img> 標簽時立即載入圖片
  • lazy:告訴用戶代理推遲圖片載入直到瀏覽器認為其需要立即載入時才去載入

5.6. decoding

decoding 屬性會告知瀏覽器應如何解碼圖片

  • async:會告知瀏覽器,圖片可以非同步解碼,有可能縮短呈現其他內容的時間
  • sync:會告知瀏覽器,同步解碼圖像,此圖片應與其他內容同時呈現
  • auto:允許瀏覽器決定什麼最適合用戶

6. 視頻載入性能

圖片並不是網路上常見的唯一媒體類型。視頻是網頁上常用的另一種媒體類型

6.1. 視頻源文件

處理媒體文件時,在操作系統中識別的文件(.mp4、.webm 等)稱為容器。一個容器包含一個或多個數據流。在大多數情況下,這是指視頻和音頻流

可以使用編解碼器壓縮每個流。例如,video.webm 可以是 WebM 容器,其中包含使用 VP9 壓縮的視頻流和使用 Vorbis 壓縮的音頻流

壓縮視頻文件的一種方法需要使用 FFmpeg

ffmpeg -i input.mov output.webm

6.2. 多種形式

使用視頻文件時,如果瀏覽器不支持所有現代格式,那麼指定多種格式可以作為後備選項

<video>
  <source src="video.webm" type="video/webm">
  <source src="video.mp4" type="video/mp4">
</video>

MP4 可用作舊版瀏覽器的後備方案

6.3. poster 屬性

視頻的海報圖片是使用 <video> 元素上的 poster 屬性添加的,該屬性會在開始播放前向用戶提示視頻內容可能是什麼:

<video poster="poster.jpg">
  <source src="video.webm" type="video/webm">
  <source src="video.mp4" type="video/mp4">
</video>

6.4. 自動播放

autoplay 在必須立即播放時使用

GIF 動畫可能會非常大,特別是當它有許多包含複雜細節的幀時。動畫 GIF 會消耗數兆位元組的數據並不罕見,這會大量消耗帶寬,以更好地用於更關鍵的資源

通常應該避免使用動畫圖片格式,因為 <video> 等效項對於此類媒體的效率要高得多

具有指定 autoplay 屬性的 <video> 元素會立即開始下載,即使這些元素位於初始視窗之外也是如此

通過結合使用 poster 屬性與 Intersection Observer API,可以將頁面配置為僅在視頻位於視窗內時下載

6.5. preload

可以使用 <video> 元素的 preload 屬性來影響為視頻資源下載的內容:

  • 設置 preload="none" 可告知瀏覽器不應預載入任何視頻內容
  • 設置 preload="metadata" 僅提取視頻元數據,例如視頻時長,可能還有一些其他粗略信息

如果要載入用戶需要開始播放的視頻,則最好設置 preload="none"

7. 優化網頁字體

網路字體是網路上的常用資源

網路字體會影響網頁在載入時和呈現時的性能

較大的字體文件可能需要一段時間才能下載完畢,並且會對 First Contentful Paint (FCP) 產生負面影響,而不正確的 font-display 值則可能會導致不必要的佈局偏移,進而導致網頁的 Cumulative Layout Shift (CLS)

7.1. @font-face

@font-face {
  font-family: "Open Sans";
  src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
}

上述代碼段定義了一個名為 Open Sansfont-family,並告知瀏覽器在哪裡可以找到相應的網頁字體資源。為了節省帶寬,瀏覽器在確定當前頁面的佈局需要網頁字體之前,不會下載該字體

7.2. preload

如果的 @font-face 聲明是在外部樣式表中定義的,瀏覽器只有在下載該樣式表之後才能開始下載這些聲明。這使得網路字體資源被延遲發現,但有一些方法可以幫助瀏覽器更快地發現網路字體

可以使用 preload 指令發起對網頁字體資源的提前請求。preload 指令可讓網頁字體在網頁載入初期被檢測到,瀏覽器會立即開始下載這些字體,無需等待樣式表完成下載和解析

preload 指令不會等到網頁上需要相應字體時再執行

<link rel="preload" as="font" href="/fonts/OpenSans-Regular-webfont.woff2" crossorigin>

請謹慎使用 preload 指令。過度使用 preload 指令可能會中斷其他關鍵資源的帶寬

字體屬於 CORS 資源,預載入字體時必須指定 crossorigin 屬性,即使這些字體是自托管的字體也是如此

7.3. 自行托管網頁字體

可以通過自行托管網頁字體來消除對第三方連接的需要。在大多數情況下,自托管網路字體比從跨源下載字體更快。如果打算自行托管網頁字體,請檢查的網站是否使用了內容分髮網絡 (CDN)、HTTP/2HTTP/3,併為網站所需的網頁字體設置正確的緩存標頭

7.4. 僅使用 WOFF2

WOFF2 獲得了廣泛的瀏覽器支持和最佳壓縮效果,比 WOFF 高出 30%。文件縮小可加快下載速度。WOFF2 格式通常是現代瀏覽器實現完全相容性所需的唯一格式

只有在需要支持舊版瀏覽器時,才可能需要使用其他格式(例如 WOFFEOTTTF)。 如果不需要支持舊版瀏覽器,則沒有理由依賴 WOFF2 以外的網頁字體格式

7.5. 設置網頁字體子集

網路字體通常包含各種不同的字形,需要這些字形來表示不同語言中使用的各種字元。如果的網頁僅以一種語言(或使用單一字母表)提供內容,可以通過子集內嵌來減小網頁字體的大小。此操作通常通過指定數字或 Unicode 碼位範圍來實現

子集是原始網頁字體文件中包含的減少的字形集。例如,的網頁可能會提供部分拉丁字元,而不是提供所有字形。根據所需的子集,移除字形可以顯著減小字體文件的大小

7.6. 字體渲染

瀏覽器發現並下載某種網頁字體後,就可以進行渲染了。預設情況下,在下載使用網頁字體的任何文本之前,瀏覽器都會阻止其渲染。可以使用 font-display CSS 屬性調整瀏覽器的文本渲染行為,並配置在網頁字體完全載入之前應顯示(或不顯示)哪些文本

7.6.1. block

font-display 的預設值為 block。使用 block 時,瀏覽器會阻止呈現使用指定網頁字體的任何文本。不同瀏覽器的行為會略有不同

7.6.2. swap

swap 是使用最廣泛的 font-display 值。swap 不會阻止渲染,並且會在交換成指定的網頁字體之前立即以後備方式顯示文本。這樣,就可以立即顯示內容,而無需等待網路字體下載完成

7.6.3. fallback

font-displayfallback 值在 blockswap 之間折衷。與 swap 不同,瀏覽器會阻止字體渲染,但只能在很短的時間內交換回退文本。不過,與 block 不同的是,阻塞期極短

7.6.4. optional

optional 是最嚴格的 font-display 值,僅在 100 毫秒內下載時才會使用網頁字體資源

如果某種網頁字體的載入用時超過該時長,便不會在網頁上使用,因此瀏覽器會使用後備字體進行當前導航,同時在後臺下載該網頁字體並將其存放在瀏覽器緩存中

7.6.5. auto

8. 代碼拆分 JavaScript

有些資源對網頁的初始載入並不重要。JavaScript 就是這樣一種資源,可通過稱為代碼拆分的技術推遲到需要時

這樣一來,可以通過減少帶寬和 CPU 爭用來提高性能,這是提高初始網頁載入速度和啟動期間的輸入響應速度的關鍵因素

載入大型 JavaScript 資源會顯著影響網頁速度。將 JavaScript 拆分為較小的區塊並僅下載網頁在啟動期間正常運行所必需的內容,可以極大地提高網頁的載入響應能力,進而提高網頁的互動到下一次繪製 (INP)

8.1. 通過代碼拆分,減少啟動期間的 JavaScript 解析和執行

Lighthouse 會在 JavaScript 執行時間超過 2 秒時發出警告,併在執行時間超過 3.5 秒時失敗

在網頁生命周期的任何時間點,過度的 JavaScript 解析和執行都是潛在的問題,因為如果用戶與網頁互動的時間與負責處理和執行 JavaScript 的主線程任務運行的時間一致,則有可能會增加互動的輸入延遲時間

可以使用 Chrome 開發者工具中的覆蓋率工具(coverage)進一步確定頁面載入期間未使用頁面的 JavaScript 的哪些部分。

image

代碼拆分是一項可以減少頁面初始 JavaScript 載荷的實用技術。它可讓將 JavaScript 軟體包拆分為兩部分:

  • 網頁載入時所需的 JavaScript 無法在任何其他時間載入
  • 可在稍後時間點載入(最常見的是用戶與頁面上的指定互動元素互動時)的其餘 JavaScript

8.2. import()

可以使用動態 import() 語法完成代碼拆分。此語法與在啟動期間請求指定 JavaScript 資源的 <script> 元素不同,該語法可在網頁生命周期的後期請求 JavaScript 資源

動態 import() 是一種類似於函數的表達式,可讓動態載入 JavaScript 模塊。 它是一種非同步操作,可用於導入模塊以響應互動或需要載入其他模塊的其他任何條件。動態 import() 與靜態import 語句不同,後者會立即導入模塊,並且要求父模塊及其所有依賴項都得到解析和執行,然後才能運行

document.querySelectorAll('#myForm input').addEventListener('blur', async () => {
  const { validateForm } = await import('/validate-form.mjs');
  validateForm();
}, { once: true });

9. 延遲載入 <iframe>元素

<iframe> 元素可能會占用大量帶寬和 CPU 處理時間

與其他類型的資源相比,<iframe> 元素消耗的帶寬通常更多。對於 <iframe> 元素,載入和渲染其中的頁面可能會消耗相當多的額外處理時間

9.1. <iframe> 元素的 loading 屬性

所有主流瀏覽器也都支持 <iframe> 元素上的 loading 屬性

loading 屬性的值及其行為與使用 loading 屬性的 <img> 元素相同:

  • eager 為預設值
  • lazy 會延遲載入 <iframe> 元素的 HTML 及其子資源,直到該元素與視窗之間的距離在預定義的距離以內

9.2. JavaScript 延遲載入

使用 Intersection Observer API

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lazy Load Images</title>
    <style>
        .spacer {
            height: 100vh;
        }
        .lazy {
            width: 100%;
            height: auto;
            display: block;
        }
    </style>
</head>
<body>
    <div class="spacer"></div>
    <img class="lazy" data-src="https://via.placeholder.com/600x400" alt="Lazy Image 1">
    <div class="spacer"></div>
    <img class="lazy" data-src="https://via.placeholder.com/600x400" alt="Lazy Image 2">
    <div class="spacer"></div>
    <img class="lazy" data-src="https://via.placeholder.com/600x400" alt="Lazy Image 3">
    <div class="spacer"></div>
</body>
</html>
<script>
// 回調函數,當目標元素的可見性發生變化時調用
const lazyLoad = (entries, observer) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.getAttribute('data-src');
            img.onload = () => img.removeAttribute('data-src');
            observer.unobserve(img);
        }
    });
};

// IntersectionObserver 配置
const options = {
    root: null, // 預設是視窗
    rootMargin: '0px',
    threshold: 0.1 // 目標元素進入視窗 10% 時觸發回調
};

// 創建 IntersectionObserver 實例
const observer = new IntersectionObserver(lazyLoad, options);
// 觀察所有具有 'lazy' 類的圖片
document.querySelectorAll('img.lazy').forEach(img => observer.observe(img));
</script>
  • root:用作視窗的元素,用於檢查目標的可見性,如果未指定或為 null,則預設為瀏覽器視窗。

  • rootMargin:根周圍的邊距

  • threshold:一個數字或一個數字數組,表示目標可見度達到多少百分比時,觀察器的回調就應該執行。如果只想在能見度超過 50% 時檢測,可以使用 0.5 的值。如果希望每次能見度超過 25% 時都執行回調,則需要指定數組 [0, 0.25, 0.5, 0.75, 1]。預設值為 0(這意味著只要有一個像素可見,回調就會運行)。值為 1.0 意味著在每個像素都可見之前,閾值不會被認為已通過。

10. 預提取、預渲染和 Service Worker 預緩存

雖然許多性能涉及到可以採取哪些措施來優化和消除不必要的資源,但建議先載入一些資源才是需要用到的,這似乎有點自相矛盾。不過,在某些情況下,可以提前載入某些資源

10.1. prefetch

可以使用 <link rel="prefetch"> 資源提示提前提取資源(包括圖片、樣式表或 JavaScript 資源)。prefetch 提示用於告知瀏覽器在不久的將來可能需要某個資源

指定 prefetch 提示後,瀏覽器可能會以最低優先順序發起對該資源的請求,以避免與當前頁面所需的資源發生爭用

預提取資源可以改善用戶體驗,因為用戶無需等待近期所需的資源下載完畢,因為可以在需要時立即從磁碟緩存中檢索這些資源

<head>
  <link rel="prefetch" as="script" href="/date-picker.js">
  <link rel="prefetch" as="style" href="/date-picker.css">
</head>

還可以通過在指向某個 HTML 文檔時指定 as="document" 屬性來預提取網頁及其所有子資源

<link rel="prefetch" href="/page" as="document">

在基於 Chromium 的瀏覽器中,可以使用 Speculation Rules API 預提取文檔。推測規則定義為包含在網頁的 HTML 中的 JSON 對象,或通過 JavaScript 動態添加:

<script type="speculationrules">
{
  "prefetch": [{
    "source": "list",
    "urls": ["/page-a", "/page-b"]
  }]
}
</script>

10.2. prerender

除了預提取資源之外,還可以提示瀏覽器在用戶導航到某個網頁之前預呈現該網頁

這種做法幾乎可以即時載入網頁,因為系統會在後臺提取和處理網頁及其資源。當用戶導航到相應頁面後,系統會將該頁面置於前臺

Speculation Rules API 支持預渲染:

<script type="speculationrules">
{
  "prerender": [
    {
      "source": "list",
      "urls": ["/page-a", "page-b"]
    }
  ]
}
</script>

10.3. Service Worker 預緩存

還可以使用 Service Worker 推測性地預提取資源

Service Worker 預緩存可以使用 CacheAPI 提取和保存資源,這樣瀏覽器無需訪問網路即可使用 Cache API 處理請求

Service Worker 預緩存使用一種非常有效的 Service Worker 緩存策略,稱為“僅緩存”策略。這種模式非常有效,因為將資源放入 Service Worker 緩存後,可在收到請求時幾乎即時提取這些資源

image

如需使用 Service Worker 預緩存資源,可以使用 Workbox

Workbox 使用預緩存清單來確定應預緩存的資源,預緩存清單是一個文件和版本控制信息列表,可作為要預緩存的資源的可信來源

[{
    url: 'script.ffaa4455.js',
    revision: null
}, {
    url: '/index.html',
    revision: '518747aa'
}]

上述代碼是一個示例清單,其中包含 script.ffaa4455.js/index.html 這兩個文件。如果資源在文件本身中包含版本信息(稱為文件哈希),則 revision 屬性可以保留為 null,因為文件已進行版本控制(例如,上述代碼中 script.ffaa4455.js 資源的 ffaa4455 屬性)。
設置後,Service Worker 可用於預緩存靜態頁面或其子資源,以加快後續頁面導航的速度

workbox.precaching.precacheAndRoute([
  '/styles/product-page.ac29.css',
  '/styles/product-page.39a1.js',
]);

Service Worker 使用的 Cache 介面和 HTTP 緩存並不相同

Cache 介面是由 JavaScript 控制的高層級緩存,而 HTTP 緩存是由 Cache-Control 標頭控制的低層級緩存

與使用資源提示或推測規則預提取或預呈現資源類似,Service Worker 預緩存會消耗網路帶寬、存儲空間和 CPU

建議僅預緩存可能會使用的資源,併在預緩存清單中指定過多的資源

11. Web Worker

用戶在瀏覽器中看到的大部分內容都在稱為主線程的單個線程上完成。不過,在某些情況下,可以啟動新線程來執行計算開銷很大的工作,以便主線程可以處理面向用戶的重要任務。執行此操作的 API 稱為 Web Worker API

JavaScript 通常被描述為一種單線程語言。這是指主線程,這是瀏覽器執行在瀏覽器中看到的大部分工作的單個線程。其中包括編寫腳本、某些類型的渲染工作、HTMLCSS 解析以及其他類型的面向用戶的工作來改善用戶體驗等

JavaScript 而言,通常只能在主線程上執行工作,但可以在 JavaScript 中註冊和使用其他線程。允許在 JavaScript 中實現多線程的功能稱為 Web Workers API

11.1. Web Worker 啟動方式

實例化 Worker

const myWebWorker = new Worker('/my-web-worker.js');

11.2. Web Worker 的限制

與在主線程上運行的 JavaScript 不同,Web Worker 無法直接訪問 window上下文,並且對其提供的 API 的訪問受到限制。Web Worker 受到以下限制條件的約束:

  • Web Worker 無法直接訪問 DOM
  • Web Worker 可以通過消息傳遞流水線與 window 上下文進行通信,這意味著 Web Worker 可以通過某種方式間接訪問 DOM
  • Web Worker 的作用域是 self,而不是 window
  • Web Worker 範圍_確實_可以訪問 JavaScript 基元和構造,以及 fetchAPI 和相當多的其他 API

11.3. Web Worker 如何與 window 通信

Web Worker 可以通過消息傳遞流水線與主線程的 window 上下文進行通信。利用此流水線,可以將數據傳送到主線程和 Web 工作器以及從主線程和 Web 工作器傳輸數據。如需將數據從 Web Worker 發送到主線程,需要在 Web Worker 的上下文 (self) 中設置 message 事件

// my-web-worker.js
self.addEventListener("message", () => {
  // Sends a message of "Hellow, window!" from the web worker:
  self.postMessage("Hello, window!");
});

然後,在主線程上 window 上下文的腳本中,可以使用另一個 message 事件接收來自網頁工作器線程的消息:

// scripts.js
// Creates the web worker:
const myWebWorker = new Worker('/js/my-web-worker.js');
// Adds an event listener on the web worker instance that listens for messages:
myWebWorker.addEventListener("message", ({ data }) => {
  // Echoes "Hello, window!" to the console from the worker.
  console.log(data);
});

三、總結

  • 本文概述了性能以及性能的重要性
  • 羅列了性能優化的點
  • 希望對大家有幫助

引用


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這段時間來,AI已經逐步走進我們的工作和生活,作為程式員來說,讓AI寫代碼已經成為稀鬆平常的操作了,今天給大家介紹一個更牛逼的操作,屏幕截屏轉化為代碼,從此前端開發更簡單 screenshot-to-code screenshot-to-code可以將任何屏幕截圖或設計轉換為乾凈的代碼,它是一個簡單 ...
  • title: Vuex 4與狀態管理實戰指南 date: 2024/6/6 updated: 2024/6/6 excerpt: 這篇文章介紹了使用Vuex進行Vue應用狀態管理的最佳實踐,包括為何需要狀態管理,Vuex的核心概念如store、actions、mutations和getters,以及 ...
  • ‍ 寫在開頭 點贊 + 收藏 學會 [webpack由淺入深]系列的內容 第一層: 瞭解一個小功能的完整流程. 看完可以滿足好奇心和應付原理級別面試. 第二層: 源碼陪讀, webpack源碼比較靈活, 自己看容易陷入迷惑. 文章里會貼出關鍵流程的代碼來輔助閱讀源碼. 如果你正在 ...
  • 工作中難免會遇到各種各樣的數據結構,較為全面的瞭解數組操作,對於複雜數據結構的處理會非常有用且節省時間。所以想在這裡總結一下工作中常用的數組操作,都是一些非常基礎的知識,大家看個樂就好~ ...
  • Promise 對象使用 ★ Promise 基本認識 Promise 是一個對象,用於表示非同步操作的最終完成(或失敗)及其結果值。它允許你關聯處理程式,這些處理程式將在非同步操作成功完成時或者失敗時調用,從而避免了更複雜的嵌套回調(即回調地獄)。Promise 對象通常用於執行非同步操作,如網路請求、 ...
  • title: Vue 3 Teleport:掌控渲染的藝術 date: 2024/6/5 updated: 2024/6/5 description: 這篇文章介紹了Vue3框架中的一個創新特性——Teleport,它允許開發者將組件內容投送到文檔對象模型(DOM)中的任意位置,即使這個位置在組件的 ...
  • ‍ 寫在開頭 點贊 + 收藏 學會 首先明確一點,localStorage是同步的 一、首先為什麼會有這樣的問題 localStorage 是 Web Storage API 的一部分,它提供了一種存儲鍵值對的機制。localStorage 的數據是持久存儲在用戶的硬碟上的 ...
  • 前端跨域問題的解決方案通常涉及幾種不同的方法,每種方法都有其特定的應用場景和優缺點。以下是一些常見的前端跨域解決方案: JSONP(JSON with Padding) 原理:利用<script>標簽沒有跨域限制的特性,通過動態創建<script>標簽並設置其src屬性為跨域請求的URL,來實現跨域 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...