图片加载的问题:
- 当代浏览器在渲染DOM树的时候, 遇到img会开辟一个HTTP线程请求图片文件,而不会阻塞DOM的渲染
- 但是在生成Render Tree后, 浏览器渲染时,会将渲染树和图片一起绘制
- 从而导致性能下降(特别是第一次加载的速度)
- HTTP线程同时只能有6个左右存在,如果图片资源过多且预先加载,会影响其他资源的请求速度
- 第一次页面加载时,如果绘制图片会消耗很多的时间,影响加载速度
解决方案:
- 采用图片懒加载(刚开始图片位置用默认图或一个空白盒子占位,等需要加载时再加载)
- 将图片base64编码
图片懒加载,顾名思义,就是当需要用图片的时候才加载图片,即看到图片才加载图片(可以理解为图片的动态加载),因此问题可以从两个方面分析:
- 图片加载方式
- 图片加载时机
1. 图片加载方式
图片加载方式主要分浏览器实现(lazyloading属性)和开发人员实现(dataset属性)
1.1 使用LazyLoading 属性
浏览器觉得懒加载这事可以交给自己做,你们开发者加个属性就好了。实在是…!
<img src="shanyue.jpg" loading="lazy" />
优点:
- 不需要开发者控制图片加载时机
缺点:
-
整个过程对于开发者来说是一个空盒子,无法做更进一步的优化。
-
浏览器的兼容性比较差,不推荐使用
1.2 使用DataSet 属性
dataset属性是HTML5提供的一种功能,可以在标准内于HTML元素中存储额外的信息——即给元素添加自定义的数据,且不会作用要页面渲染上。
使用方法:
-
在元素上通过
data-*
设置属性信息,其中*为自定义的数据名<img src="" data-image="shanyue.jpg"/>
-
通过
getAttribute
获取属性信息let imageObj = document.querySelector("img"), trueImg = imageObj.getAttribute("data-image"); imageObj.src = trueImg; imageObj.onload = function(){ imageObj['style']['opacity'] = 1; // 保证没有加载完成时,就仅显示占位;加载完成后,将占位隐藏 }; imgObj.removeAttribute['data-image']
优点:
- 整个过程开发可以控制
- 兼容性好
缺点:
- 需要开发者自己控制图片加载时机
2. 图片加载时机
2.1 滚动事件+盒子模型
动态: 通过滚动事件来处理
加载:通过 clientHeight + scrollTop >= offsetTop来触发
优化:节流(throttle)
2.2 滚动事件+getBoundingClientRect()
提升点:提供API直接获取元素相对于视窗的位置(兼容性挺好的,Chrome2,IE4)
动态: 通过滚动事件来处理
加载:通过 getBoundingClientRect.top <= window.innerHeight来触发
优化: 节流(throttle)
2.3 IntersectionObserver
提升点:将滚动事件+获取元素相对于视窗的位置+节流三部分整合起来(兼容性较差,IE不支持,Chrome51+)
使用步骤:
- 创建intersectionObserver对象:
var observer = new IntersectionObserver(cb, {threshold: [0.5]})
- cb:回调函数,通过其中的参数(changes)获取所有监听对象的状态
- threshold: 阈值,如上,当显示50%的时候触发对象改变
- 监听图片对象或其他对象:
observer.observe(obj)
- 移除监听:
observer.unobserve(obj)
欢迎大家进入我的博客参观: 七月&花语