css
和内联js
移除文件下载,较小文件体积SSR
加速首屏加载(耗费服务端资源),有利于SEO
优化。 首屏利用服务端渲染,后续交互采用客户端渲染Perfomance API
衡量和分析各种性能指标对于确保
web
应用的速度非常重要。Performance API
提供了重要的内置指标,并能够将你自己的测量结果添加到浏览器的性能时间线(performance timeline)
中。性能时间线使用高精度的时间戳,且可以在开发者工具中显示。你还可以将相关数据发送到用于分析的端点,以根据时间记录性能指标。
关键时间节点 | 描述 | 含义 |
---|---|---|
TTFB | time to first byte(首字节时间) | 从请求到数据返回第一个字节所消耗时间 |
TTI | Time to Interactive(可交互时间) | DOM树构建完毕,代表可以绑定事件 |
DCL | DOMContentLoaded (事件耗时) | 当 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发 |
L | onLoad (事件耗时) | 当依赖的资源全部加载完毕之后才会触发 |
FP | First Paint(首次绘制) | 第一个像素点绘制到屏幕的时间 |
FCP | First Contentful Paint(首次内容绘制) | 首次绘制任何文本,图像,非空白节点的时间 |
FMP | First Meaningful paint(首次有意义绘制) | 首次有意义绘制是页面可用性的量度标准 |
LCP | Largest Contentful Paint(最大内容渲染) | 在viewport中最大的页面元素加载的时间 |
FID | First Input Delay(首次输入延迟) | 用户首次和页面交互(单击链接,点击按钮等)到页面响应交互的时间 |
<div style="background:red;height:100px;width:100px"></div>
<h1 elementtiming="meaningful"></h1>
<script>
window.onload = function () {
let ele = document.createElement('h1');
ele.innerHTML = 'zf';
document.body.appendChild(ele)
}
setTimeout(() => {
const {
fetchStart,
requestStart,
responseStart,
domInteractive,
domContentLoadedEventEnd,
loadEventStart
} = performance.timing;
let TTFB = responseStart - requestStart; // ttfb
let TTI = domInteractive - fetchStart; // tti
let DCL = domContentLoadedEventEnd - fetchStart // dcl
let L = loadEventStart - fetchStart;
console.log(TTFB, TTI, DCL, L)
const paint = performance.getEntriesByType('paint');
const FP = paint[0].startTime;
const FCP = paint[1].startTime; // 2s~4s
}, 2000);
let FMP;
new PerformanceObserver((entryList, observer) => {
let entries = entryList.getEntries();
FMP = entries[0];
observer.disconnect();
console.log(FMP)
}).observe({ entryTypes: ['element'] });
let LCP;
new PerformanceObserver((entryList, observer) => {
let entries = entryList.getEntries();
LCP = entries[entries.length - 1];
observer.disconnect();
console.log(LCP); // 2.5s-4s
}).observe({ entryTypes: ['largest-contentful-paint'] });
let FID;
new PerformanceObserver((entryList, observer) => {
let firstInput = entryList.getEntries()[0];
if (firstInput) {
FID = firstInput.processingStart - firstInput.startTime;
observer.disconnect();
console.log(FID)
}
}).observe({ type: 'first-input', buffered: true });
</script>
减少HTTP请求数,合并JS
、CSS
,合理内嵌CSS
、JS
合理设置服务端缓存,提高服务器处理速度。 (强制缓存、对比缓存)
// Expires/Cache-Control Etag/if-none-match/last-modified/if-modified-since
避免重定向,重定向会降低响应速度 (301,302)
使用dns-prefetch
,进行DNS
预解析
采用域名分片技术,将资源放到不同的域名下。接触同一个域名最多处理6个TCP链接问题。
采用CDN
加速加快访问速度。(指派最近、高度可用)
gzip
压缩优化 对传输资源进行体积压缩 (html
,js
,css
)
加载数据优先级 : preload
(预先请求当前页面需要的资源) prefetch
(将来页面中使用的资源) 将数据缓存到HTTP缓存中
<link rel="preload" href="style.css" as="style">
Reflow
: 添加元素、删除元素、修改大小、移动元素位置、获取位置相关信息Repaint
:页面中元素样式的改变并不影响它在文档流中的位置。我们应当尽可能减少重绘和回流
JavaScript强制将计算样式和布局操作提前到当前的任务中
<div id="app"></div>
<script>
function reflow() {
let el = document.getElementById('app');
let node = document.createElement('h1');
node.innerHTML = 'hello';
el.appendChild(node);
// 强制同步布局
console.log(app.offsetHeight);
}
requestAnimationFrame(reflow)
</script>
在一段js
代码中,反复执行布局操作,就是布局抖动
function reflow(){
let el = document.getElementById('app');
let node = document.createElement('h1');
node.innerHTML = 'hello';
el.appendChild(node);
// 强制同步布局
console.log(app.offsetHeight);
}
window.addEventListener('load',function(){
for(let i = 0 ; i<100;i++){
reflow();
}
});
css3
动画图片格式:
jpg
:适合色彩丰富的照片、banner图;不适合图形文字、图标(纹理边缘有锯齿),不支持透明度png:
适合纯色、透明、图标,支持半透明;不适合色彩丰富图片,因为无损存储会导致存储体积大gif
:适合动画,可以动的图标;不支持半透明,不适和存储彩色图片webp
:适合半透明图片,可以保证图片质量和较小的体积svg
格式图片:相比于jpg
和jpg
它的体积更小,渲染成本过高,适合小且色彩单一的图标;图片优化:
避免空src
的图片
减小图片尺寸,节约用户流量
img
标签设置alt
属性, 提升图片加载失败时的用户体验
原生的loading:lazy
图片懒加载
<img loading="lazy" src="./images/1.jpg" width="300" height="450" />
不同环境下,加载不同尺寸和像素的图片
<img src="./images/1.jpg" sizes="(max-width:500px) 100px,(max-width:600px) 200px" srcset="./images/1.jpg 100w, ./images/3.jpg 200w">
对于较大的图片可以考虑采用渐进式图片
采用base64URL
减少图片请求
采用雪碧图合并图标图片等
HTML
优化HTML
:代码简洁清晰,利于搜索引擎,便于团队开发iframes
使用 (iframe
会阻塞onload
事件可以动态加载iframe
)CSS
优化减少伪类选择器、减少样式层数、减少使用通配符
避免使用CSS
表达式,CSS
表达式会频繁求值, 当滚动页面,或者移动鼠标时都会重新计算 (IE6,7
)
background-color: expression( (new Date()).getHours()%2 ? "red" : "yellow" );
删除空行、注释、减少无意义的单位、css
进行压缩
使用外链css
,可以对CSS
进行缓存
添加媒体字段,只加载有效的css
文件
<link href="index.css" rel="stylesheet" media="screen and (min-width:1024px)" />
CSS contain
属性,将元素进行隔离
减少@import使用,由于@import采用的是串行加载
JS
优化通过async
、defer
异步加载文件
减少DOM操作,缓存访问过的元素
操作不直接应用到DOM上,而应用到虚拟DOM上。最后一次性的应用到DOM上。
使用webworker
解决程序阻塞问题
IntersectionObserver
const observer = new IntersectionObserver(function(changes) {
changes.forEach(function(element, index) {
if (element.intersectionRatio > 0) {
observer.unobserve(element.target);
element.target.src = element.target.dataset.src;
}
});
});
function initObserver() {
const listItems = document.querySelectorAll('img');
listItems.forEach(function(item) {
observer.observe(item);
});
}
initObserver();
虚拟滚动 vertual-scroll-list
requestAnimationFrame
、requestIdleCallback
尽量避免使用eval
, 消耗时间久
使用事件委托,减少事件绑定个数。
尽量使用canvas动画、CSS
动画
@font-face {
font-family: "Bmy";
src: url("./HelloQuincy.ttf");
font-display: block;
/* block 3s 内不显示, 如果没加载完毕用默认的 */
/* swap 显示老字体 在替换 */
/* fallback 缩短不显示时间, 如果没加载完毕用默认的 ,和block类似*/
/* optional 替换可能用字体 可能不替换*/
}
body {
font-family: "Bmy"
}
`FOUT(Flash Of Unstyled Text)` 等待一段时间,如果没加载完成,先显示默认。加载后再进行切换。
`FOIT(Flash Of Invisible Text)`字体加载完毕后显示,加载超时降级系统字体 (白屏)