在当今快节奏的数字世界中,网站性能在决定任何在线企业的成功方面起着至关重要的作用。
一个快速、响应迅速且用户友好的网站不仅可以吸引和留住访问者,还有助于提高搜索引擎排名、提高转化率和改善用户体验 (UX)。
作为软件工程师或 Web 开发人员,必须在项目中优先考虑性能优化技术。
在本文中,我将分享通过各种方法来优化 JavaScript 代码,包括最小化文件大小、减少网络请求、利用缓存和异步加载,以及采用最佳实践来确保更快的加载时间和改进的用户体验。
1、最小化文件大小
影响网站加载时间的关键因素之一是提供给用户的文件大小。
较大的文件需要更多时间来下载,并可能导致你的网站加载缓慢,从而导致用户体验欠佳。JavaScript 文件也不例外,优化它们的大小是提高网站性能的基本步骤。
缩小是在不影响其功能的情况下删除不必要的字符(例如空格、注释和换行符)并缩短 JavaScript 代码中的变量名称的过程。这导致文件大小显着减小,进而导致更快的加载时间和更高的性能。
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);
如你所见,代码的缩小版本明显更小,删除了不必要的字符并缩短了变量名。这会导致更小的文件大小和更快的加载时间,而不会影响代码的功能。
2、文件压缩
压缩是另一种用于减小文件大小的技术,可以缩短网站加载时间。
它的工作原理是应用算法来压缩文件中的数据,使文件更小而不失去其功能。当浏览器请求压缩文件时,它会即时解压缩,以便正确呈现和执行内容。
有两种广泛使用的 JavaScript 文件压缩算法:Gzip 和 Brotli。
Gzip 长期以来一直是事实上的标准,但是由 Google 开发的更新的压缩算法 Brotli 因其优越的压缩比和速度而变得越来越流行。
01)Gzip 和 Brotli 压缩方法
Gzip:Gzip 是一种广泛采用的压缩算法,可以显着减小 JavaScript 文件的大小。Gzip 使用 Deflate 算法,该算法结合了 LZ77 和霍夫曼编码以高效地压缩数据。
Brotli:Brotli 是 Google 开发的一种较新的压缩算法,提供比 Gzip 更好的压缩率。Brotli 结合使用 LZ77、霍夫曼编码和一种新颖的上下文建模技术来实现更高的压缩率。
在大多数情况下,Brotli 在压缩比和速度方面都优于 Gzip,这使其成为现代 Web 应用程序的一个有吸引力的选择。
02)压缩的服务器端配置
要提供压缩的 JavaScript 文件,你需要将服务器配置为使用 Gzip 或 Brotli 压缩文件,然后再将它们发送到客户端。
具体配置步骤因您的服务器类型(例如 Apache、Nginx 或 Node.js)而异。以下是如何在流行的服务器类型上启用压缩的简要概述:
- Apache:为 Gzip 压缩启用 mod_deflate 模块或为 Brotli 压缩启用 mod_brotli 模块,并在 .htaccess 文件或虚拟主机配置中配置适当的设置。
- Nginx:在 Nginx 配置文件中使用 gzip 或 brotli 指令启用压缩并指定设置。
- Node.js:对于基于 Node.js 的服务器,您可以将中间件(例如用于 Gzip 的压缩或用于 Brotli 的 shrink-ray-current)与 Express 或类似的 Web 框架结合使用。
请务必注意,某些浏览器可能不支持 Brotli 压缩,因此,最好将你的服务器配置为在不支持 Brotli 时回退到 Gzip。
这确保了所有浏览器的最佳兼容性和性能。
3、捆绑以减少网络请求
减少网络请求的数量对于提高网站性能至关重要,因为每个请求都会增加延迟并消耗带宽。
01)捆绑说明
捆绑是将多个 JavaScript 文件组合成一个文件的过程。这减少了浏览器需要发出的 HTTP 请求的数量,从而加快了加载过程。捆绑可以显着提高网站性能,尤其是对于具有大量较小 JavaScript 文件的网站。
02)捆绑工具
有几种流行的工具可用于捆绑 JavaScript 文件,每种工具都有其独特的特性和优势。
以下是一些广泛使用的捆绑工具:
- Webpack:Webpack 是一个功能强大且灵活的模块捆绑器,它不仅可以捆绑 JavaScript 文件,还可以处理样式表和图像等其他资产。它具有强大的插件生态系统,允许你根据需要扩展其功能。
- Rollup:Rollup 是另一个流行的 JavaScript 模块打包器,专注于简单性和性能。它特别适合捆绑库,可以输出多种格式,包括 CommonJS、AMD 和 ES 模块。
03)JavaScript 代码示例:捆绑多个文件
为了演示捆绑过程,我们假设你有三个独立的 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));
})();
如你所见,捆绑文件将原始文件中的所有必要代码包含在一个独立的单元中,从而减少了加载脚本所需的网络请求数。
通过最小化请求数量,你可以减少浏览器下载和处理必要资源所需的时间,从而缩短加载时间并提供更灵敏的用户体验。
4、为图像和图标使用 Sprite
利用图像精灵是另一种减少网络请求和提高网站性能的技术。
精灵本质上是一个包含多个较小图像(例如图标或 UI 元素)的图像文件。
01)、图像精灵的解释
图像精灵是一个大图像,包含多个以网格状图案排列的小图像。在 CSS 或 JavaScript 代码中,可以通过指定图像的位置和尺寸来引用精灵中的各个图像。
此方法允许仅通过单个 HTTP 请求加载许多图像,从而减少延迟并缩短加载时间。
02)、创建图像精灵
要创建图像精灵,可以使用各种工具,例如:
- Sprite 生成器工具:SpritePad 或 Stitches 等在线工具允许您上传多张图像并自动生成一个 sprite,以及相应的 CSS 代码。
- 图像编辑软件:Adobe Photoshop 或 GIMP 等程序可用于通过在新文件中排列较小的图像并将结果导出为单个图像来手动创建精灵。
03)、CSS 代码示例:使用图像精灵
假设您有一个名为“icons.png”的精灵图像,其中包含多个图标,你可以使用以下 CSS 代码将各个图标显示为不同元素的背景图像:
.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;
}
每个图标类指定相应图标在 sprite 中的位置,无需额外的 HTTP 请求即可显示所需的图像。
通过将这些较小的图像组合成一个文件,浏览器只需要请求一个图像,减少了 HTTP 请求的数量。
5、延迟加载资源
延迟加载是一种将非关键资源的加载推迟到实际需要时才加载的技术。
这意味着你无需预先加载所有资源,而只需加载即时视图所需的资源,而其余的则在它们变得相关时获取。延迟加载可以大大缩短网站的初始加载时间和感知性能,尤其是在处理图像或冗长脚本等大型资产时。
01)、JavaScript 代码示例:实现延迟加载
为了说明延迟加载,让我们使用仅当图像在视口中可见时才加载图像的示例。这可以使用 IntersectionObserver API 来实现。
这是一个简单的实现:
首先,向你的图像元素添加一个 data-src 属性,其中包含实际的图像源:
<img data-src="path/to/image.jpg" class="lazy-load" alt="An example image">
然后,创建一个脚本来设置 IntersectionObserver 以在图像进入视口时加载图像:
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 监视 .lazy-load 图像是否进入视口。检测到图像时,会将其 data-src 属性分配给 src 属性,从而触发实际的图像下载。加载图像后,将删除延迟加载类,并且不会观察到图像。
使用这种简单的延迟加载技术,你可以确保只加载当前查看的图像,减少网络请求的数量并缩短网站的初始加载时间。
注意:将此代码提取到名为 useLazyImageObserver 的自定义组件中可能是个好主意。然后,您可以使用像 Bit 这样的开源工具链通过简单的 npm i @bit/your-username/use-location 在所有项目中发布、版本化和重用它。在这里了解更多。
6、利用缓存
网站性能是提供出色用户体验的关键因素。
提高性能的一项基本技术是缓存,它允许浏览器存储网站资源的副本,例如,图像、样式表和脚本。这减少了重复下载的需要并加快了加载时间。在本节中,我们将探讨缓存的概念以及如何利用它来提高网站的性能。
01)、浏览器缓存
浏览器缓存是一种使网络浏览器能够在本地存储网站文件副本的机制。当用户重新访问你的站点时,浏览器可以从缓存中加载这些资源,而不是再次下载它们,从而加快加载时间并减少服务器负载。
通过配置你的服务器以提供适当的缓存标头,你可以控制缓存哪些资源以及缓存多长时间。
02)、缓存控制和 ETag 标头
用于控制浏览器缓存的两个重要标头是 Cache-Control 和 ETag。
Cache-Control 标头允许你设置缓存指令,例如缓存中资源的最长期限或是否应重新验证。
例如,可以使用 Cache-Control:public, max-age=3600 表示资源可以缓存一小时。
ETag 标头为特定版本的资源提供唯一标识符(通常是哈希)。当浏览器请求资源时,它会发送缓存中的 ETag 值。如果服务器的 ETag 值与浏览器发送的值匹配,则服务器响应 304 Not Modified 状态,浏览器使用缓存的版本。此机制有助于确保浏览器始终拥有最新版本的资源。
03)、在服务器端配置缓存
要启用浏览器缓存,你需要将服务器配置为为你的资源提供适当的标头。此过程因你的服务器软件而异。
例如,在 Apache 服务器中,您可以使用 .htaccess 文件来设置缓存标头:
此配置为 CSS、JS、JPG 和 PNG 文件设置 Cache-Control 标头,允许它们缓存 24 小时。
通过利用浏览器缓存,你可以显着减少用户重新访问您的站点时需要获取的数据量,从而加快加载时间并改善整体用户体验。
7、利用异步加载
随着网站变得越来越复杂,管理 JavaScript 文件的加载对于性能变得越来越重要。
默认情况下,浏览器同步加载脚本,阻塞渲染过程,直到脚本完全加载并执行。异步加载允许脚本与其他资源并行加载,防止它们阻塞渲染并改善整体加载时间。
在本节中,我们将讨论如何利用 JavaScript 文件的异步加载来增强网站的性能。
01)、JavaScript 文件的异步加载
异步加载允许浏览器下载和执行 JavaScript 文件,而不会阻止页面其余部分的呈现。
这种方法不仅可以加快网站的初始呈现速度,还可以降低脚本缓慢或无响应导致延迟的风险。
通过使用 async 和 defer 属性,您可以控制 JavaScript 文件的加载和执行行为。
02)、使用 Async 和 Defer 属性
async 和 defer 属性可以添加到 <script> 标签以启用异步加载:
- async:async 属性告诉浏览器在不阻塞渲染的情况下下载脚本。下载脚本后,浏览器将暂停渲染以执行它。这对于不依赖于其他脚本或完全加载 DOM 的脚本很有用。
- defer:defer 属性指示浏览器在不阻塞渲染的情况下下载脚本,但会延迟执行直到 DOM 被完全解析。这对于依赖于 DOM 或其他脚本的脚本很有用。
重要的是要注意这些属性只能与外部脚本文件一起使用,因为它们对内联脚本没有影响。
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 完全解析后执行。同时,analytics.js 加载了 async 属性,允许它独立于页面的其余部分下载和执行。
通过为你的 JavaScript 文件利用异步加载,您可以最大限度地减少渲染阻塞资源并提高您网站的性能和用户体验。
8、采用最佳实践来缩短加载时间并改进用户体验
网站优化是一个持续的过程,为了最大限度地提高性能,必须跟上最新的最佳实践。
01)、代码拆分
代码拆分是一种技术,涉及将 JavaScript 代码分解成更小、更易于管理的块,这些块仅在需要时加载。这减少了需要下载和解析的代码量,从而缩短了初始加载时间并使交互更加流畅。代码拆分对于单页应用程序 (SPA) 和具有复杂功能的大型网站特别有用。
有几个工具可以帮助实现代码拆分,例如 Webpack 和 React.lazy:
- Webpack:这个流行的捆绑器提供对代码拆分的内置支持。使用其动态 import() 函数,您可以按需加载 JavaScript 模块,减少初始加载时间。
- React.lazy:如果您使用的是 React,React.lazy 函数可让您在需要时延迟加载组件,从而进一步优化您的应用程序。
- bit:越来越多的工程团队正在采用微前端作为将大型项目代码拆分为独立组件的一种方式。
02)、JavaScript 代码示例:实现代码拆分
下面是使用 Webpack 和 React 进行代码拆分的示例:
// 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 在需要时延迟加载,防止它阻塞应用程序的初始呈现。
03)、使用内容分发网络 (CDN)
内容分发网络 (CDN) 是一种通过在全球多个服务器上分发你的内容来提高网站性能的强大方式。
这确保用户可以从靠近其位置的服务器访问您网站的资源,从而减少延迟并加快加载时间。将你的网站与 CDN 集成可以极大地改善用户体验,尤其是对于地理位置较远的用户。
04)、优化 DOM 操作和事件处理
高效的 DOM 操作对于提高网站性能至关重要。文档对象模型 (DOM) 表示网页的结构,对其进行操作可能会占用大量资源。通过优化用于 DOM 操作的 JavaScript 代码,您可以最大限度地减少性能影响并创建更流畅的用户体验。
05)、JavaScript 代码示例:高效的 DOM 操作
下面是优化 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 操作,减少回流和重绘的次数,并提高性能。
06)、浏览器开发者工具
大多数现代浏览器都带有内置的开发人员工具,可以帮助你监控和优化网站的性能。
例如,Chrome DevTools 和 Firefox Developer Tools 提供性能分析、网络监控和 JavaScript 调试等功能。通过使用这些工具,你可以确定代码中的瓶颈和需要改进的地方。
07)、在线工具
还有一些在线工具可以帮助你分析和优化你的网站性能。一些受欢迎的选项包括:
- Google PageSpeed Insights:此工具分析您的网站并提供改进其性能的建议。它考虑了服务器响应时间、图像优化和 JavaScript 加载技术等因素。
- WebPageTest:WebPageTest 是一款综合性能测试工具,可提供有关网站加载时间、呈现等的详细信息。您还可以将您网站的性能与其他网站进行比较,或者从不同的位置和设备运行测试。
通过了解最新的最佳实践并监控你网站的性能指标,可以确保你的网站保持快速、高效和用户友好。
总结
在今天的文章中,我分享了几种 JavaScript 优化技术,以帮助你提高网站的性能和用户体验。从最小化文件大小和减少网络请求到利用缓存和异步加载,这些方法都可以对你网站的加载时间产生重大影响。
我希望你能发现本指南内容丰富且有用。同时,也欢迎你在留言区中分享你关于 JavaScript 优化的想法、经验和问题。让我们互相学习,共同学习,共同不断提高我们网站的性能!