懒加载也叫做延迟加载、按需加载,指的是在长网页中延迟加载图片数据,是一种较好的网页性能优化的方式。在比较长的网页或应用中,如果图片很多,所有的图片都被加载出来,而用户只能看到可视窗口的那一部分图片数据,这样就浪费了性能。
如果使用图片的懒加载就可以解决以上问题。在滚动屏幕之前,可视化区域之外的图片不会进行加载,在滚动屏幕时才加载。这样使得网页的加载速度更快,减少了服务器的负载。懒加载适用于图片较多,页面列表较长(长列表)的场景中。
图片的加载是由 src
引起的,当对 src
赋值时,浏览器就会请求图片资源。根据这个原理,我们使用 HTML5 的 data-xxx
属性来储存图片的路径,在需要加载图片的时候,将 data-xxx
中图片的路径赋值给src,这样就实现了图片的按需加载,即懒加载。
注意:data-xxx 中的 xxx 可以自定义,这里我们使用
data-src
来定义。
懒加载的实现重点在于确定用户需要加载哪张图片,在浏览器中,可视区域内的资源就是用户需要的资源。所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可。
window.innerHeight
是浏览器可视区的高度document.body.scrollTop
|| document.documentElement.scrollTop
是浏览器滚动的过的距离imgs.offsetTop
是元素顶部距离文档顶部的高度(包括滚动条的距离)img.offsetTop < window.innerHeight + document.body.scrollTop;
<div class="container">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
</div>
<script>
var imgs = document.querySelectorAll('img')
function lozyLoad(){
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var winHeight = window.innerHeight;
for(var i=0; i<imgs.length; i++){
if(imgs[i].offsetTop < scrollTop + winHeight){
imgs[i].src = imgs[i].getAttribute(data-src);
}
}
}
window.onscroll = lozyLoad();
</script>
当渲染树中部分或者全部元素的尺寸、结构或者属性发生变化时,浏览器会重新渲染部分或者全部文档的过程就称为回流。
下面这些操作会导致回流:
在触发回流(重排)的时候,由于浏览器渲染页面是基于流式布局的,所以当触发回流时,会导致周围的 DOM 元素重新排列,它的影响范围有两种:
当页面中某些元素的样式发生变化,但是不会影响其在文档流中的位置时,浏览器就会对元素进行重新绘制,这个过程就是重绘。
下面这些操作会导致重绘:
color
、background
相关属性:background-color
、background-image
等outline
相 关 属 性 : outline-color
、 outline-width
、text-decoration
border-radius
、visibility
、box-shadow
注意: 当触发回流时,一定会触发重绘,但是重绘不一定会引发回流。
table
布局, 一个小的改动可能会使整个 table
进行重新布局absolute
或者 fixed
,使元素脱离文档流,这样他们发生变化就不会影响其他元素documentFragment
,在它上面应用所有 DOM 操作,最后再把它添加到文档中display: none
,操作结束后再把它显示出来。因为在display
属性为 none
的元素上进行的 DOM 操作不会引发回流和重绘。对于如何优化动画,我们知道,一般情况下,动画需要频繁的操作DOM,就就会导致页面的性能问题,我们可以将动画的 position
属性设置为 absolute
或者 fixed
,将动画脱离文档流,这样他的回流就不会影响到页面了。
MDN 中对 documentFragment
的解释:
DocumentFragment
,文档片段接口,一个没有父对象的最小文档对象。它被作为一个轻量版的 Document
使用,就像标准的 document
一样,存储由节点(nodes
)组成的文档结构。与 document
相比,最大的区别是 DocumentFragment
不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。
当我们把一个 DocumentFragment
节点插入文档树时,插入的不是DocumentFragment
自身,而是它的所有子孙节点。在频繁的 DOM 操作时,我们就可以将 DOM 元素插入 DocumentFragment
,之后一次性的将所有的子孙节点插入文档中。和直接操作 DOM 相比,将DocumentFragment
节点插入 DOM 树时,不会触发页面的重绘,这样就大大提高了页面的性能。
函数节流是指规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。节流可以使用在 scroll
函数的事件监听上,通过事件节流来降低事件调用的频率。
节流函数的适?场景:
resize
函数防抖是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。这可以使用在一些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求。
防抖函数的应用场景:
lodash.debounce
function debounce(fn, wait) {
var timer = null;
return function(){
var context = this,
args = [...arguments];
//如果此时存在定时器的话,则取消之前的定时器重新计时
if(timer){
clearTimeout(timer);
timer = null;
}
//设置定时器,使事件间隔指定事件后执行
timer = setTimeout(() =>{
fn.apply(context, args);
}, wait);
};
}
//时间戳版
function throttle(fn, delay){
var preTime = Date.now();
return function(){
var context = this,
args = [...arguments];
nowTime = Date.now();
//如果两次时间间隔超过了指定时间,则执行函数
if(nowTime - preTime >= delay){
preTime = Date.now();
return fn.apply(context, args);
}
};
}
//定时器版
function throttle(fun, wait){
let timeout = null;
return function(){
let context = this;
let args = [...arguments];
if(!timeout){
timeout = setTimeout(() => {
fun.apply(context, args);
timeout = null;
}, wait);
}
};
}
?webpack 优化前端性能是指优化 webpack 的输出结果,让打包的最终结果在浏览器运?快速?效。
UglifyJsPlugin
和 ParallelUglifyPlugin
来压缩JS?件, 利? cssnano (css-loader?minimize
)来压缩 cssloader
的publicPath
参数来修改资源路径Tree Shaking
: 将代码中永远不会?到的?段删除掉。可以通过在启动 webpack 时追加参数 –optimize-minimize
来实现Code Splitting
: 将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利?浏览器缓存SplitChunksPlugin
插件来进?公共模块抽取, 利?浏览器缓存可以?期缓存这些?需频繁变动的公共代码CommonsChunkPlugin
来提取公共代码externals
配置来提取常?库DllPlugin
和 DllReferencePlugin
预编译资源模块 通过DllPlugin
来对那些我们引?但是绝对不会修改的 npm
包来进?预编译,再通过 DllReferencePlugin
将预编译的模块加载进来。Happypack
实现多线程加速编译webpack-uglify-parallel
来提升 uglifyPlugin
的压缩速度。原理上 webpack-uglify-parallel
采?了多核并?压缩来提升压缩速度Tree-shaking
和 Scope Hoisting
来剔除多余代码