이번에는 프론트엔드 웹페이지의 기본 성능 최적화와 주의사항에 대해 알려드리겠습니다. 다음은 실제 사례를 살펴보겠습니다.
페이지 최적화
정적 리소스 압축
빌딩 도구(webpack, gulp)를 사용하여 이미지, 스크립트, 스타일과 같은 웹페이지 정적 리소스를 적절하게 압축하세요.
CSS 스프라이트 이미지, base64 인라인 이미지
사이트의 작은 아이콘을 하나의 이미지로 병합하고 CSS 위치 지정을 사용하여 해당 아이콘을 적절하게 캡처합니다.
상단 스타일, 하단 스크립트
페이지는 단계별 렌더링 프로세스이며, 상단 스타일은 사용자에게 페이지를 더 빠르게 표시할 수 있습니다. 페이지 뒤의 리소스 다운로드.
외부 링크 CSS 및 js를 사용하세요
여러 페이지가 공개 정적 리소스를 참조하므로 리소스 재사용으로 추가 http 요청이 줄어듭니다.
src가 비어 있는 이미지를 피하세요
불필요한 http 요청을 피하세요.
<!-- 空src的图片依然会发起http请求 --> <img src="" alt="image" />
html에서 이미지 크기 조정을 피하세요
큰 이미지를 로드한 다음 축소하는 대신 필요에 따라 이미지에 지정된 크기를 사용해 보세요.
<!-- 实际图片尺寸为600x300,在html中缩放为了200x100 --> <img src="/static/images/a.png" width="200" height="100" alt="image" />
preload preloading
preload 속성을 링크 태그의 rel로 설정하면 브라우저가 기본 렌더링 메커니즘이 개입하기 전에 리소스를 미리 로드할 수 있습니다. 이 메커니즘은 리소스를 더 일찍 얻을 수 있으며 페이지 초기화를 차단하지 않습니다.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link ref="preload" href="style.css" as="style"> <link ref="preload" href="main.js" as="script"> <link ref="stylesheet" href="style.css"> </head> <body> <script src="main.js"></script> </body> </html>
css 및 js 파일은 예제에 미리 로드되어 있으며 후속 페이지 렌더링에 사용되면 즉시 호출됩니다.
다른 유형의 리소스를 로드하기 위해 as 유형을 지정할 수 있습니다.
style
script
video
audio
image
font
문서
...
이 방법도 사용 가능 도메인 전체에 걸쳐 리소스를 미리 로드하려면 crossorigin 속성을 설정하기만 하면 됩니다.
<link rel="preload" href="fonts/cicle_fina-webfont.woff2" as="font" type="font/woff2" crossorigin="anonymous">
CSS
Selector
높은 것부터 낮은 것까지의 선택기 우선 순위는 다음과 같습니다.
ID 선택기
클래스 선택기
태그 선택기
인접 선택기
h1 + p{ margin-top: 15px; }
h1 요소 바로 뒤에 나타나는 단락을 선택합니다. h1 및 p 요소에는 공통 상위 요소가 있습니다.
하위 선택기
h1 > strong {color:red;}
하위 선택기
h1 em {color:red;}
와일드카드 선택기
속성 선택기
*[title] {color:red;} img[alt] {border: 5px solid red;}
의사 클래스 선택기
선택기 사용 경험:
클래스 선택기 선호, 여러 레이어 교체 가능 태그 선택기
사용 ID 선택기는 효율적이지만 페이지에서 고유하며 팀 공동 작업 및 유지 관리에 도움이 되지 않습니다.
선택기 상속을 합리적으로 사용하세요.
CSS 표현을 사용하지 마세요.
선택기 수준 줄이기
이전 선택기의 우선순위에 따라 여러 수준의 선택기 중첩을 피해야 하며 가급적이면 3수준을 넘지 않아야 합니다.
.container .text .logo{ color: red; } /*改成*/ .container .text-logo{ color: red; }
페이지 스타일 파일을 간소화하고 사용하지 않는 스타일을 제거하세요
브라우저는 중복된 스타일 일치를 수행하므로 렌더링 시간에 영향을 줍니다. 또한 스타일 파일이 너무 크면 로딩 속도에도 영향을 줍니다.
CSS 상속을 사용하여 코드 양 줄이기
CSS의 상속 가능한 속성을 사용하면 상위 요소가 스타일을 설정하고 하위 요소는 다시 설정할 필요가 없습니다.
색상, 글꼴 크기, 글꼴 계열 등과 같은 일반적인 상속 가능 속성: 위치, 표시, 부동 등과 같은 상속 불가능한 속성
속성 값이 0이면 단위가 추가되지 않습니다.
CSS 속성 값이 0이면 코드 양을 줄이기 위해 단위가 추가되지 않습니다.
.text{ width: 0px; height: 0px; } /*改成*/ .text{ width: 0; height: 0; }
JavaScript
使用事件委托
给多个同类DOM元素绑定事件使用事件委托。
<ul id="container"> <li class="list">1</li> <li class="list">2</li> <li class="list">3</li> </ul>
// 不合理的方式:给每个元素都绑定click事件 $('#container .list').on('click', function() { var text = $(this).text(); console.log(text); }); // 事件委托方式:利用事件冒泡机制将事件统一委托给父元素 $('#container').on('click', '.list', function() { var text = $(this).text(); console.log(text); });
需要注意的是,虽然使用事件委托时都可以将事件委托给document来做,但这是不合理的,一个是容易造成事件误判,另一个是作用域链查找效率低。应该选择最近的父元素作为委托对象。
使用事件委托除了性能上更优,动态创建的DOM元素也不需要再绑定事件。
DOMContentLoaded
可在DOM元素加载完毕(DOMContentLoaded)后开始处理DOM树,不必等到所有图片资源下载完后再处理。
// 原生javascript document.addEventListener("DOMContentLoaded", function(event) { console.log("DOM fully loaded and parsed"); }, false); // jquery $(document).ready(function() { console.log("ready!"); }); // $(document).ready()的简化版 $(function() { console.log("ready!"); });
预加载和懒加载
预加载
利用浏览器空闲时间预先加载将来可能会用到的资源,如图片、样式、脚本。
无条件预加载
一旦onload触发,立即获取将来需要用到的资源。
图片资源预加载。(3种实现图片预加载的方式)。
基于用户行为的预加载
对于用户行为可能进行的操作进行判断,预先加载将来可能需要用到的资源。
当用户在搜索输入框输入时,预先加载搜索结果页可能用到的资源;
当用户去操作一个Tab选项卡时,默认显示其中一个,当要去点击(click)其他选项时,在鼠标hover时,就可先加载将来会用到的资源;
懒加载
除页面初始化需要的内容或组件之外,其他都可以延迟加载,如剪切图片的js库、不在可视范围的图片等等。
图片懒加载。(判断图片是否在可视区域范围内,若在,则将真实路径赋给图片)
避免全局查找
任何一个非局部变量在函数中被使用超过一次时,都应该将其存储为局部变量。
function updateUI(){ var imgs = document.getElementsByTagName("img"); for (var i=0, len=imgs.length; i < len; i++){ imgs[i].title = document.title + " image " + i; } var msg = document.getElementById("msg"); msg.innerHTML = "Update complete."; }
在上面函数中多次使用到document全局变量,尤其在for循环中。因此将document全局变量存储为局部变量再使用是更优的方案。
function updateUI(){ var doc = document; var imgs = doc.getElementsByTagName("img"); for (var i=0, len=imgs.length; i < len; i++){ imgs[i].title = doc.title + " image " + i; } var msg = doc.getElementById("msg"); msg.innerHTML = "Update complete."; }
值得注意的一点是,在javascript代码中,任何没有使用var声明的变量都会变为全局变量,不正当的使用会带来性能问题。
避免不必要的属性查询
使用变量和数组要比访问对象上的属性更有效率,因为对象必须在原型链中对拥有该名称的属性进行搜索。
// 使用数组 var values = [5, 10]; var sum = values[0] + values[1]; alert(sum); // 使用对象 var values = { first: 5, second: 10}; var sum = values.first + values.second; alert(sum);
上面代码中,使用对象属性来计算。一次两次的属性查找不会造成性能问题,但若需要多次查找,如在循环中,就会影响性能。
在获取单个值的多重属性查找时,如:
var query = window.location.href.substring(window.location.href.indexOf("?"));
应该减少不必要的属性查找,将window.location.href缓存为变量。
var url = window.location.href; var query = url.substring(url.indexOf("?"));
函数节流
假设有一个搜索框,给搜索框绑定onkeyup事件,这样每次鼠标抬起都会发送请求。而使用节流函数,能保证用户在输入时的指定时间内的连续多次操作只触发一次请求。
<input type="text" id="input" value="" />
// 绑定事件 document.getElementById('input').addEventListener('keyup', function() { throttle(search); }, false); // 逻辑函数 function search() { console.log('search...'); } // 节流函数 function throttle(method, context) { clearTimeout(method.tId); method.tId = setTimeout(function() { method.call(context); }, 300); }
节流函数的应用场景不局限搜索框,比如页面的滚动onscroll,拉伸窗口onresize等都应该使用节流函数提升性能。
最小化语句数
语句数量的多少也是影响操作执行速度的因素。
将多个变量声明合并为一个变量声明
// 使用多个var声明 var count = 5; var color = "blue"; var values = [1,2,3]; var now = new Date(); // 改进后 var count = 5, color = "blue", values = [1,2,3], now = new Date();
改进的版本是只使用一个var声明,由逗号隔开。当变量很多时,只使用一个var声明要比单个var分别声明快很多。
使用数组和对象字面量
使用数组和对象字面量的方式代替逐条语句赋值的方式。
var values = new Array(); values[0] = 123; values[1] = 456; values[2] = 789; // 改进后 var values = [123, 456, 789];
var person = new Object(); person.name = "Jack"; person.age = 28; person.sayName = function(){ alert(this.name); }; // 改进后 var person = { name : "Jack", age : 28, sayName : function(){ alert(this.name); } };
字符串优化
字符串拼接
早期浏览器未对加号拼接字符串方式优化。由于字符串是不可变的,就意味着要使用中间字符串来存储结果,因此频繁的创建和销毁字符串是导致它效率低下的原因。
var text = "Hello"; text+= " "; text+= "World!";
把字符串添加到数组中,再调用数组的join方法转成字符串,就避免了使用加法运算符。
var arr = [], i = 0; arr[i++] = "Hello"; arr[i++] = " "; arr[i++] = "World!"; var text = arr.join('');
现在的浏览器都对字符串加号拼接做了优化,所以在大多数情况下,加法运算符还是首选。
减少回流和重绘
在浏览器渲染过程中,涉及到回流和重绘,这是一个损耗性能的过程,应注意在脚本操作时减少会触发回流和重绘的动作。
回流:元素的几何属性发生了变化,需要重新构建渲染树。渲染树发生变化的过程,就叫回流;
重绘:元素的几何尺寸没有变化,某个元素的CSS样式(背景色或颜色)发生了变化。
触发重排或重绘的操作有哪些?
调整窗口大小
修改字体
增加或者移除样式表
内容变化,比如用户在框中输入文字
操作class属性
脚本操作DOM(增加、删除或修改DOM元素)
计算offsetWidth和offsetHeight属性
设置style属性的值
如何减少重排和重绘,提升网页性能?
1、脚本操作DOM元素
将DOM元素设置为display:none,设置过程中会触发一次回流,但之后可以随意改动,修改完后再显示;
将元素clone到内存中再进行操作,修改完后重新替换元素。
2、修改元素的样式
尽量批量修改,而不是逐条修改;
预先设定好id、class,再设置元素的className。
3、为元素添加动画时将元素CSS样式设为position:fixed或position:absolute,元素脱离文档流后不会引起回流。
4、在调整窗口大小、输入框输入、页面滚动等场景时使用节流函数(上面已提到过)。
HTTP
浏览器缓存
合理设置浏览器缓存是网页优化的重要手段之一。
Expires 和 Cache-Control
Expires出自HTTP1.0,Cache-Control出自HTTP1.1,同时设置两者时,Cache-Control 会覆盖 Expires。
Expires指定的是实际过期日期而不是秒数。但Expires存在一些问题,如服务器时间不同步或不准确。所以最好使用剩余秒数而不是绝对时间来表达过期时间。
Cache-Control可设置max-age值,单位秒,指定缓存过期时间。如:Cache-Control: max-age=3600。
ETag 和 Last-Modified
ETag 和 Last-Modified都由服务器返回在response headers中,其中ETag的优先级比Last-Modified高,也就是说服务器会优先判断ETag的值。
ETag是附加到文档上的任意标签,可能是文档的序列号或版本号,或者是文档内容的校验等。当文档改变时ETag值也会随之改变。与ETag相关的是 If-None-Match,当浏览器发起请求时,会在If-None-Match字段携带ETag的值发给服务器;
Last-Modified是文档在服务器端最后被修改的时间。与Last-Modified相关的是If-Modified-Since,当浏览器发起请求时,会在If-Modified-Since字段携带Last-Modified的值发送给服务器。
强缓存和协商缓存
캐시 유형: 강력한 캐시와 협상된 캐시. 둘의 차이점은 강력한 캐시는 서버에 요청을 보내지 않지만 협상된 캐시는 일치가 성공하면 304 Not Modified를 반환하고 일치에 실패하면 반환한다는 것입니다. 200; 브라우저는 먼저 강력한 캐시를 확인하고 강력한 캐시가 누락된 경우 협상 캐시 확인을 수행합니다.
브라우저 캐시를 구성하는 방법
웹 서버의 반환 응답에 만료 및 캐시 제어를 추가합니다.
nginx 또는 Apache의 구성 파일에 만료 및 캐시 제어를 구성합니다.
HTTP 요청을 줄여야 하는 이유
HTTP 요청을 줄이기 위한 조치는 성능 최적화에서 큰 부분을 차지합니다. 예를 들어 CSS 스프라이트 이미지를 사용하여 여러 이미지 요청 교체, 빈 src 이미지 방지, 인라인 그림 사용 , 외부 링크, 캐싱 등을 사용하는 CSS 및 js
URL 입력부터 페이지 로딩 완료까지의 과정은 다음과 같습니다:
DNS 확인
TCP 연결
HTTP 요청 및 응답
브라우저 렌더링 페이지 연결을 끊으세요
이 기사의 사례를 읽으신 후 방법을 마스터하셨다고 생각합니다. 더 흥미로운 정보를 보려면 PHP 중국어 웹사이트의 다른 관련 기사를 주목하세요!
css+transition을 통해 보이는 애니메이션과 보이지 않는 애니메이션 만들기
위 내용은 프런트엔드 웹페이지의 기본 성능 최적화의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!