性能优化,一直做为前端的一个热点问题,做为一个优秀的前端开发人员,性能优化时必备技能。本文将从减小http请求次数、减小单次请求资源大小、渲染优化、资源加载优化等四个大方向,下分诸多小方向,全面总结经常使用前端优化方法。 (内容较多请看目录)css
浏览器缓存机制有四个方面,它们按照获取资源时请求的优先级依次排列以下:
html
CDN 的核心点有两个,一个是缓存,一个是回源。
“缓存”就是说咱们把资源 copy一份到CDN服务器上这个过程,“回源”就是说CDN发现本身没有这个资源(通常是缓存的数据过时了),转头向根服务器(或者它的上层服务器)去要这个资源的过程。
CDN每每被用来存放静态资源。所谓“静态资源”,就是像 JS、CSS、图片等不须要业务服务器进行计算即得的资源。用户能够从一个较优的服务器获取数据,从而达到快速访问,并减小源站负载压力的目的。
另外,CDN的域名必须和主业务服务器的域名不同,要不,同一个域名下面的Cookie各处跑,浪费了性能流量的开销,CDN域名放在不一样的域名下,能够完美地避免了没必要要的 Cookie 的出现!前端
将公共的js、css样式合并为一个大文件。
根据不一样页面的需求单独合并所需js、css文件。web
尽可能避免使用重定向,当页面发生了重定向,就会延迟整个HTML文档的传输。在HTML文档到达以前,页面中不会呈现任何东西,也没有任何组件会被下载,下降了用户体验。
若是必定要使用重定向,如http重定向到https,要使用301永久重定向,而不是302临时重定向。由于,若是使用302,则每一次访问http,都会被重定向到https的页面。而永久重定向,在第一次从http重定向到https以后,每次访问http,会直接返回https的页面。浏览器
css压缩,就是进行简单的压缩,压缩空白等。
图片压缩,主要也是减少体积,在不影响观感的前提下,能够删除一些可有可无的色彩。另外可使用webp格式图片。
gzip压缩主要是针对html文件来讲的,它能够将html中重复的部分进行一个打包,屡次复用。
js混淆能够有简单的压缩(将空白字符删除)、丑化(将一些变量缩小)、或者对js进行混淆加密。缓存
CSS 选择符是从右到左进行匹配的,好比 #myul li {}实际开销至关高。所以须要对选择符进行优化,主要有以下几方面:性能优化
重绘不必定致使回流,回流必定会致使重绘。bash
从上面能够知道,DOM改变容易引发回流和重绘,所以咱们要减小DOM操做。 例子剖析,以下代码:服务器
for(var count=0;count<10000;count++){
document.getElementById('container').innerHTML+='<span>我是一个小测试</span>' //咱们每一次循环都调用 DOM 接口从新获取了一次 container 元素,额外开销
}
复制代码
进化一babel
// 只获取一次container
let container = document.getElementById('container')
for(let count=0;count<10000;count++){
container.innerHTML += '<span>我是一个小测试</span>'
}
复制代码
进化二
考虑JS 的运行速度,比 DOM 快得多这个特性。咱们减小 DOM 操做的核心思路,就是让 JS 去给 DOM 分压。
//减小没必要要的DOM更改
let container = document.getElementById('container')
let content = ''
for(let count=0;count<10000;count++){
// 先对内容进行操做
content += '<span>我是一个小测试</span>'
}
// 内容处理好了,最后再触发DOM的更改
container.innerHTML = content
复制代码
进化三
在 DOM Fragment 中,DocumentFragment 接口表示一个没有父级文件的最小文档对象。它被当作一个轻量版的 Document 使用,用于存储已排好版的或还没有打理好格式的XML片断。由于 DocumentFragment 不是真实 DOM 树的一部分,它的变化不会引发 DOM 树的从新渲染的操做(reflow),且不会致使性能等问题。
let container = document.getElementById('container')
// 建立一个DOM Fragment对象做为容器
let content = document.createDocumentFragment()
for(let count=0;count<10000;count++){
// span此时能够经过DOM API去建立
let oSpan = document.createElement("span")
oSpan.innerHTML = '我是一个小测试'
// 像操做真实DOM同样操做DOM Fragment对象
content.appendChild(oSpan)
}
// 内容处理好了,最后再触发真实DOM的更改
container.appendChild(content)
复制代码
进化四
当涉及到过万调数据进行渲染,并且要求不卡住画面,如何解决? 如何在不卡住页面的状况下渲染数据,也就是说不能一次性将几万条都渲染出来,而应该一次渲染部分 DOM,那么就能够经过 requestAnimationFrame 来每 16 ms 刷新一次。
setTimeout(() => {
// 插入十万条数据
const total = 100000
// 一次插入 20 条,若是以为性能很差就减小
const once = 20
// 渲染数据总共须要几回
const loopCount = total / once
let countOfRender = 0
let ul = document.querySelector('ul')
function add() {
// 优化性能,插入不会形成回流
const fragment = document.createDocumentFragment()
for (let i = 0; i < once; i++) {
const li = document.createElement('li')
li.innerText = Math.floor(Math.random() * total)
fragment.appendChild(li)
}
ul.appendChild(fragment)
countOfRender += 1
loop()
}
function loop() {
if (countOfRender < loopCount) {
window.requestAnimationFrame(add)
}
}
loop()
}, 0)
复制代码
事件委托是指将事件监听器注册在父级元素上,因为子元素的事件会经过事件冒泡的方式向上传播到父节点,所以,能够由父节点的监听函数统一处理多个子元素的事件。利用事件委托,能够减小内存使用,提升性能及下降代码复杂度。
当用户进行滚动,触发scroll事件,用户的每一次滚动都将触发咱们的监听函数。函数执行是吃性能的,频繁地响应某个事件将形成大量没必要要的页面计算。所以,咱们须要针对那些有可能被频繁触发的事件做进一步地优化。节流与防抖就颇有必要了!
//节流函数
function throttle(fn,time){
var last = 0;
return function(){
var context = this;
var now = Date.now();
if (now - last >= time){
fn.apply(this, arguments);
last = now;
}
};
}
//防抖函数
function debounce(fn, time){
return function(){
var context = this;
clearTimeout(timeId);
timeId = setTimeout(function(){
fn.apply(context, arguements);
}, time);
};
}
复制代码
资源懒加载和资源预加载都是一种错峰操做,在浏览器忙碌的时候不作操做,浏览器空间时,再加载资源,优化了网络性能。