深入了解加快網(wǎng)站加載時間的 JavaScript 優(yōu)化技術(shù)
在當(dāng)今快節(jié)奏的數(shù)字世界中,網(wǎng)站性能在決定任何在線企業(yè)的成功方面起著至關(guān)重要的作用。
一個快速、響應(yīng)迅速且用戶友好的網(wǎng)站不僅可以吸引和留住訪問者,還有助于提高搜索引擎排名、提高轉(zhuǎn)化率和改善用戶體驗 (UX)。
作為軟件工程師或 Web 開發(fā)人員,必須在項目中優(yōu)先考慮性能優(yōu)化技術(shù)。
在本文中,我將分享通過各種方法來優(yōu)化 JavaScript 代碼,包括最小化文件大小、減少網(wǎng)絡(luò)請求、利用緩存和異步加載,以及采用最佳實(shí)踐來確保更快的加載時間和改進(jìn)的用戶體驗。
1、最小化文件大小
影響網(wǎng)站加載時間的關(guān)鍵因素之一是提供給用戶的文件大小。
較大的文件需要更多時間來下載,并可能導(dǎo)致你的網(wǎng)站加載緩慢,從而導(dǎo)致用戶體驗欠佳。JavaScript 文件也不例外,優(yōu)化它們的大小是提高網(wǎng)站性能的基本步驟。
縮小是在不影響其功能的情況下刪除不必要的字符(例如空格、注釋和換行符)并縮短 JavaScript 代碼中的變量名稱的過程。這導(dǎo)致文件大小顯著減小,進(jìn)而導(dǎo)致更快的加載時間和更高的性能。
01)、JavaScript 代碼示例:縮小前后
讓我們看一個簡單的例子來理解縮小對文件大小的影響:
縮小前:
// Function to calculate the sum of two numbers
function addNumbers(num1, num2) {
return num1 + num2;
}
// Use the function to calculate the sum of 3 and 5
const sum = addNumbers(3, 5);
// Log the result to the console
console.log("The sum is:", sum);
縮小后:
function addNumbers(n,e){return n+e}const sum=addNumbers(3,5);console.log("The sum is:",sum);
如你所見,代碼的縮小版本明顯更小,刪除了不必要的字符并縮短了變量名。這會導(dǎo)致更小的文件大小和更快的加載時間,而不會影響代碼的功能。
2、文件壓縮
壓縮是另一種用于減小文件大小的技術(shù),可以縮短網(wǎng)站加載時間。
它的工作原理是應(yīng)用算法來壓縮文件中的數(shù)據(jù),使文件更小而不失去其功能。當(dāng)瀏覽器請求壓縮文件時,它會即時解壓縮,以便正確呈現(xiàn)和執(zhí)行內(nèi)容。
有兩種廣泛使用的 JavaScript 文件壓縮算法:Gzip 和 Brotli。
Gzip 長期以來一直是事實(shí)上的標(biāo)準(zhǔn),但是由 Google 開發(fā)的更新的壓縮算法 Brotli 因其優(yōu)越的壓縮比和速度而變得越來越流行。
01)Gzip 和 Brotli 壓縮方法
Gzip:Gzip 是一種廣泛采用的壓縮算法,可以顯著減小 JavaScript 文件的大小。Gzip 使用 Deflate 算法,該算法結(jié)合了 LZ77 和霍夫曼編碼以高效地壓縮數(shù)據(jù)。
Brotli:Brotli 是 Google 開發(fā)的一種較新的壓縮算法,提供比 Gzip 更好的壓縮率。Brotli 結(jié)合使用 LZ77、霍夫曼編碼和一種新穎的上下文建模技術(shù)來實(shí)現(xiàn)更高的壓縮率。
在大多數(shù)情況下,Brotli 在壓縮比和速度方面都優(yōu)于 Gzip,這使其成為現(xiàn)代 Web 應(yīng)用程序的一個有吸引力的選擇。
02)壓縮的服務(wù)器端配置
要提供壓縮的 JavaScript 文件,你需要將服務(wù)器配置為使用 Gzip 或 Brotli 壓縮文件,然后再將它們發(fā)送到客戶端。
具體配置步驟因您的服務(wù)器類型(例如 Apache、Nginx 或 Node.js)而異。以下是如何在流行的服務(wù)器類型上啟用壓縮的簡要概述:
- Apache:為 Gzip 壓縮啟用 mod_deflate 模塊或為 Brotli 壓縮啟用 mod_brotli 模塊,并在 .htaccess 文件或虛擬主機(jī)配置中配置適當(dāng)?shù)脑O(shè)置。
- Nginx:在 Nginx 配置文件中使用 gzip 或 brotli 指令啟用壓縮并指定設(shè)置。
- Node.js:對于基于 Node.js 的服務(wù)器,您可以將中間件(例如用于 Gzip 的壓縮或用于 Brotli 的 shrink-ray-current)與 Express 或類似的 Web 框架結(jié)合使用。
請務(wù)必注意,某些瀏覽器可能不支持 Brotli 壓縮,因此,最好將你的服務(wù)器配置為在不支持 Brotli 時回退到 Gzip。
這確保了所有瀏覽器的最佳兼容性和性能。
3、捆綁以減少網(wǎng)絡(luò)請求
減少網(wǎng)絡(luò)請求的數(shù)量對于提高網(wǎng)站性能至關(guān)重要,因為每個請求都會增加延遲并消耗帶寬。
01)捆綁說明
捆綁是將多個 JavaScript 文件組合成一個文件的過程。這減少了瀏覽器需要發(fā)出的 HTTP 請求的數(shù)量,從而加快了加載過程。捆綁可以顯著提高網(wǎng)站性能,尤其是對于具有大量較小 JavaScript 文件的網(wǎng)站。
02)捆綁工具
有幾種流行的工具可用于捆綁 JavaScript 文件,每種工具都有其獨(dú)特的特性和優(yōu)勢。
以下是一些廣泛使用的捆綁工具:
- Webpack:Webpack 是一個功能強(qiáng)大且靈活的模塊捆綁器,它不僅可以捆綁 JavaScript 文件,還可以處理樣式表和圖像等其他資產(chǎn)。它具有強(qiáng)大的插件生態(tài)系統(tǒng),允許你根據(jù)需要擴(kuò)展其功能。
- Rollup:Rollup 是另一個流行的 JavaScript 模塊打包器,專注于簡單性和性能。它特別適合捆綁庫,可以輸出多種格式,包括 CommonJS、AMD 和 ES 模塊。
03)JavaScript 代碼示例:捆綁多個文件
為了演示捆綁過程,我們假設(shè)你有三個獨(dú)立的 JavaScript 文件:
// main.js
import { greet } from './greeting.js';
import { calculate } from './math.js';
console.log(greet('John'));
console.log(calculate(5, 3));
// greeting.js
export function greet(name) {
return `Hello, ${name}!`;
}
// math.js
export function calculate(x, y) {
return x * y;
}
使用 Webpack 或 Rollup 等捆綁工具,你可以將這些文件組合成一個捆綁文件。輸出可能看起來像這樣:
(function () {
'use strict';
function greet(name) {
return `Hello, ${name}!`;
}
function calculate(x, y) {
return x * y;
}
console.log(greet('John'));
console.log(calculate(5, 3));
})();
如你所見,捆綁文件將原始文件中的所有必要代碼包含在一個獨(dú)立的單元中,從而減少了加載腳本所需的網(wǎng)絡(luò)請求數(shù)。
通過最小化請求數(shù)量,你可以減少瀏覽器下載和處理必要資源所需的時間,從而縮短加載時間并提供更靈敏的用戶體驗。
4、為圖像和圖標(biāo)使用 Sprite
利用圖像精靈是另一種減少網(wǎng)絡(luò)請求和提高網(wǎng)站性能的技術(shù)。
精靈本質(zhì)上是一個包含多個較小圖像(例如圖標(biāo)或 UI 元素)的圖像文件。
01)、圖像精靈的解釋
圖像精靈是一個大圖像,包含多個以網(wǎng)格狀圖案排列的小圖像。在 CSS 或 JavaScript 代碼中,可以通過指定圖像的位置和尺寸來引用精靈中的各個圖像。
此方法允許僅通過單個 HTTP 請求加載許多圖像,從而減少延遲并縮短加載時間。
02)、創(chuàng)建圖像精靈
要創(chuàng)建圖像精靈,可以使用各種工具,例如:
- Sprite 生成器工具:SpritePad 或 Stitches 等在線工具允許您上傳多張圖像并自動生成一個 sprite,以及相應(yīng)的 CSS 代碼。
- 圖像編輯軟件:Adobe Photoshop 或 GIMP 等程序可用于通過在新文件中排列較小的圖像并將結(jié)果導(dǎo)出為單個圖像來手動創(chuàng)建精靈。
03)、CSS 代碼示例:使用圖像精靈
假設(shè)您有一個名為“icons.png”的精靈圖像,其中包含多個圖標(biāo),你可以使用以下 CSS 代碼將各個圖標(biāo)顯示為不同元素的背景圖像:
.icon {
width: 32px;
height: 32px;
background-image: url('icons.png');
}
.icon-search {
background-position: 0 0;
}
.icon-settings {
background-position: -32px 0;
}
.icon-user {
background-position: -64px 0;
}
每個圖標(biāo)類指定相應(yīng)圖標(biāo)在 sprite 中的位置,無需額外的 HTTP 請求即可顯示所需的圖像。
通過將這些較小的圖像組合成一個文件,瀏覽器只需要請求一個圖像,減少了 HTTP 請求的數(shù)量。
5、延遲加載資源
延遲加載是一種將非關(guān)鍵資源的加載推遲到實(shí)際需要時才加載的技術(shù)。
這意味著你無需預(yù)先加載所有資源,而只需加載即時視圖所需的資源,而其余的則在它們變得相關(guān)時獲取。延遲加載可以大大縮短網(wǎng)站的初始加載時間和感知性能,尤其是在處理圖像或冗長腳本等大型資產(chǎn)時。
01)、JavaScript 代碼示例:實(shí)現(xiàn)延遲加載
為了說明延遲加載,讓我們使用僅當(dāng)圖像在視口中可見時才加載圖像的示例。這可以使用 IntersectionObserver API 來實(shí)現(xiàn)。
這是一個簡單的實(shí)現(xiàn):
首先,向你的圖像元素添加一個 data-src 屬性,其中包含實(shí)際的圖像源:
<img data-src="path/to/image.jpg" class="lazy-load" alt="An example image">
然后,創(chuàng)建一個腳本來設(shè)置 IntersectionObserver 以在圖像進(jìn)入視口時加載圖像:
document.addEventListener('DOMContentLoaded', function () {
const lazyImages = [].slice.call(document.querySelectorAll('.lazy-load'));
if ('IntersectionObserver' in window) {
const lazyImageObserver = new IntersectionObserver(function (entries, observer) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
const lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove('lazy-load');
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach(function (lazyImage) {
lazyImageObserver.observe(lazyImage);
});
}
});
在此示例中,IntersectionObserver 監(jiān)視 .lazy-load 圖像是否進(jìn)入視口。檢測到圖像時,會將其 data-src 屬性分配給 src 屬性,從而觸發(fā)實(shí)際的圖像下載。加載圖像后,將刪除延遲加載類,并且不會觀察到圖像。
使用這種簡單的延遲加載技術(shù),你可以確保只加載當(dāng)前查看的圖像,減少網(wǎng)絡(luò)請求的數(shù)量并縮短網(wǎng)站的初始加載時間。
注意:將此代碼提取到名為 useLazyImageObserver 的自定義組件中可能是個好主意。然后,您可以使用像 Bit 這樣的開源工具鏈通過簡單的 npm i @bit/your-username/use-location 在所有項目中發(fā)布、版本化和重用它。在這里了解更多。
6、利用緩存
網(wǎng)站性能是提供出色用戶體驗的關(guān)鍵因素。
提高性能的一項基本技術(shù)是緩存,它允許瀏覽器存儲網(wǎng)站資源的副本,例如,圖像、樣式表和腳本。這減少了重復(fù)下載的需要并加快了加載時間。在本節(jié)中,我們將探討緩存的概念以及如何利用它來提高網(wǎng)站的性能。
01)、瀏覽器緩存
瀏覽器緩存是一種使網(wǎng)絡(luò)瀏覽器能夠在本地存儲網(wǎng)站文件副本的機(jī)制。當(dāng)用戶重新訪問你的站點(diǎn)時,瀏覽器可以從緩存中加載這些資源,而不是再次下載它們,從而加快加載時間并減少服務(wù)器負(fù)載。
通過配置你的服務(wù)器以提供適當(dāng)?shù)木彺鏄?biāo)頭,你可以控制緩存哪些資源以及緩存多長時間。
02)、緩存控制和 ETag 標(biāo)頭
用于控制瀏覽器緩存的兩個重要標(biāo)頭是 Cache-Control 和 ETag。
Cache-Control 標(biāo)頭允許你設(shè)置緩存指令,例如緩存中資源的最長期限或是否應(yīng)重新驗證。
例如,可以使用 Cache-Control:public, max-age=3600 表示資源可以緩存一小時。
ETag 標(biāo)頭為特定版本的資源提供唯一標(biāo)識符(通常是哈希)。當(dāng)瀏覽器請求資源時,它會發(fā)送緩存中的 ETag 值。如果服務(wù)器的 ETag 值與瀏覽器發(fā)送的值匹配,則服務(wù)器響應(yīng) 304 Not Modified 狀態(tài),瀏覽器使用緩存的版本。此機(jī)制有助于確保瀏覽器始終擁有最新版本的資源。
03)、在服務(wù)器端配置緩存
要啟用瀏覽器緩存,你需要將服務(wù)器配置為為你的資源提供適當(dāng)?shù)臉?biāo)頭。此過程因你的服務(wù)器軟件而異。
例如,在 Apache 服務(wù)器中,您可以使用 .htaccess 文件來設(shè)置緩存標(biāo)頭:
此配置為 CSS、JS、JPG 和 PNG 文件設(shè)置 Cache-Control 標(biāo)頭,允許它們緩存 24 小時。
通過利用瀏覽器緩存,你可以顯著減少用戶重新訪問您的站點(diǎn)時需要獲取的數(shù)據(jù)量,從而加快加載時間并改善整體用戶體驗。
7、利用異步加載
隨著網(wǎng)站變得越來越復(fù)雜,管理 JavaScript 文件的加載對于性能變得越來越重要。
默認(rèn)情況下,瀏覽器同步加載腳本,阻塞渲染過程,直到腳本完全加載并執(zhí)行。異步加載允許腳本與其他資源并行加載,防止它們阻塞渲染并改善整體加載時間。
在本節(jié)中,我們將討論如何利用 JavaScript 文件的異步加載來增強(qiáng)網(wǎng)站的性能。
01)、JavaScript 文件的異步加載
異步加載允許瀏覽器下載和執(zhí)行 JavaScript 文件,而不會阻止頁面其余部分的呈現(xiàn)。
這種方法不僅可以加快網(wǎng)站的初始呈現(xiàn)速度,還可以降低腳本緩慢或無響應(yīng)導(dǎo)致延遲的風(fēng)險。
通過使用 async 和 defer 屬性,您可以控制 JavaScript 文件的加載和執(zhí)行行為。
02)、使用 Async 和 Defer 屬性
async 和 defer 屬性可以添加到 <script> 標(biāo)簽以啟用異步加載:
- async:async 屬性告訴瀏覽器在不阻塞渲染的情況下下載腳本。下載腳本后,瀏覽器將暫停渲染以執(zhí)行它。這對于不依賴于其他腳本或完全加載 DOM 的腳本很有用。
- defer:defer 屬性指示瀏覽器在不阻塞渲染的情況下下載腳本,但會延遲執(zhí)行直到 DOM 被完全解析。這對于依賴于 DOM 或其他腳本的腳本很有用。
重要的是要注意這些屬性只能與外部腳本文件一起使用,因為它們對內(nèi)聯(lián)腳本沒有影響。
03)、JavaScript 代碼示例:異步和延遲用法
讓我們看一個在 HTML 文件中使用 async 和 defer 屬性的例子:
<!DOCTYPE html>
<html>
<head>
<!-- Using the defer attribute -->
<script src="main.js" defer></script>
</head>
<body>
<!-- Using the async attribute -->
<script src="analytics.js" async></script>
</body>
</html>
在此示例中,main.js 加載了 defer 屬性,確保它不會阻塞渲染,并在 DOM 完全解析后執(zhí)行。同時,analytics.js 加載了 async 屬性,允許它獨(dú)立于頁面的其余部分下載和執(zhí)行。
通過為你的 JavaScript 文件利用異步加載,您可以最大限度地減少渲染阻塞資源并提高您網(wǎng)站的性能和用戶體驗。
8、采用最佳實(shí)踐來縮短加載時間并改進(jìn)用戶體驗
網(wǎng)站優(yōu)化是一個持續(xù)的過程,為了最大限度地提高性能,必須跟上最新的最佳實(shí)踐。
01)、代碼拆分
代碼拆分是一種技術(shù),涉及將 JavaScript 代碼分解成更小、更易于管理的塊,這些塊僅在需要時加載。這減少了需要下載和解析的代碼量,從而縮短了初始加載時間并使交互更加流暢。代碼拆分對于單頁應(yīng)用程序 (SPA) 和具有復(fù)雜功能的大型網(wǎng)站特別有用。
有幾個工具可以幫助實(shí)現(xiàn)代碼拆分,例如 Webpack 和 React.lazy:
- Webpack:這個流行的捆綁器提供對代碼拆分的內(nèi)置支持。使用其動態(tài) import() 函數(shù),您可以按需加載 JavaScript 模塊,減少初始加載時間。
- React.lazy:如果您使用的是 React,React.lazy 函數(shù)可讓您在需要時延遲加載組件,從而進(jìn)一步優(yōu)化您的應(yīng)用程序。
- bit:越來越多的工程團(tuán)隊正在采用微前端作為將大型項目代碼拆分為獨(dú)立組件的一種方式。
02)、JavaScript 代碼示例:實(shí)現(xiàn)代碼拆分
下面是使用 Webpack 和 React 進(jìn)行代碼拆分的示例:
// Importing the React and React.lazy libraries
import React, { lazy, Suspense } from 'react';
// Loading the component lazily using React.lazy
const MyComponent = lazy(() => import('./MyComponent'));
function App() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
</div>
);
}
export default App;
在此示例中,MyComponent 在需要時延遲加載,防止它阻塞應(yīng)用程序的初始呈現(xiàn)。
03)、使用內(nèi)容分發(fā)網(wǎng)絡(luò) (CDN)
內(nèi)容分發(fā)網(wǎng)絡(luò) (CDN) 是一種通過在全球多個服務(wù)器上分發(fā)你的內(nèi)容來提高網(wǎng)站性能的強(qiáng)大方式。
這確保用戶可以從靠近其位置的服務(wù)器訪問您網(wǎng)站的資源,從而減少延遲并加快加載時間。將你的網(wǎng)站與 CDN 集成可以極大地改善用戶體驗,尤其是對于地理位置較遠(yuǎn)的用戶。
04)、優(yōu)化 DOM 操作和事件處理
高效的 DOM 操作對于提高網(wǎng)站性能至關(guān)重要。文檔對象模型 (DOM) 表示網(wǎng)頁的結(jié)構(gòu),對其進(jìn)行操作可能會占用大量資源。通過優(yōu)化用于 DOM 操作的 JavaScript 代碼,您可以最大限度地減少性能影響并創(chuàng)建更流暢的用戶體驗。
05)、JavaScript 代碼示例:高效的 DOM 操作
下面是優(yōu)化 DOM 操作的示例:
// Inefficient DOM manipulation
const list = document.querySelector('#list');
for (let i = 0; i < 1000; i++) {
const item = document.createElement('li');
item.textContent = `Item ${i}`;
list.appendChild(item);
}
// Efficient DOM manipulation
const list = document.querySelector('#list');
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const item = document.createElement('li');
item.textContent = `Item ${i}`;
fragment.appendChild(item);
}
list.appendChild(fragment);
在高效示例中,我們使用 DocumentFragment 來批處理 DOM 操作,減少回流和重繪的次數(shù),并提高性能。
06)、瀏覽器開發(fā)者工具
大多數(shù)現(xiàn)代瀏覽器都帶有內(nèi)置的開發(fā)人員工具,可以幫助你監(jiān)控和優(yōu)化網(wǎng)站的性能。
例如,Chrome DevTools 和 Firefox Developer Tools 提供性能分析、網(wǎng)絡(luò)監(jiān)控和 JavaScript 調(diào)試等功能。通過使用這些工具,你可以確定代碼中的瓶頸和需要改進(jìn)的地方。
07)、在線工具
還有一些在線工具可以幫助你分析和優(yōu)化你的網(wǎng)站性能。一些受歡迎的選項包括:
- Google PageSpeed Insights:此工具分析您的網(wǎng)站并提供改進(jìn)其性能的建議。它考慮了服務(wù)器響應(yīng)時間、圖像優(yōu)化和 JavaScript 加載技術(shù)等因素。
- WebPageTest:WebPageTest 是一款綜合性能測試工具,可提供有關(guān)網(wǎng)站加載時間、呈現(xiàn)等的詳細(xì)信息。您還可以將您網(wǎng)站的性能與其他網(wǎng)站進(jìn)行比較,或者從不同的位置和設(shè)備運(yùn)行測試。
通過了解最新的最佳實(shí)踐并監(jiān)控你網(wǎng)站的性能指標(biāo),可以確保你的網(wǎng)站保持快速、高效和用戶友好。
總結(jié)
在今天的文章中,我分享了幾種 JavaScript 優(yōu)化技術(shù),以幫助你提高網(wǎng)站的性能和用戶體驗。從最小化文件大小和減少網(wǎng)絡(luò)請求到利用緩存和異步加載,這些方法都可以對你網(wǎng)站的加載時間產(chǎn)生重大影響。
我希望你能發(fā)現(xiàn)本指南內(nèi)容豐富且有用。同時,也歡迎你在留言區(qū)中分享你關(guān)于 JavaScript 優(yōu)化的想法、經(jīng)驗和問題。讓我們互相學(xué)習(xí),共同學(xué)習(xí),共同不斷提高我們網(wǎng)站的性能!