1. 资源加载优先级
在浏览器发起网络请求时,并非每个字节都具有相同的优先级,所以,浏览器通常会对所要加载的内容进行推测,将相对重要的信息先呈现给用户。比如浏览器一般会先加载CSS,再去加载JavaScript脚本和图像文件。当然,浏览器的判断并不一定都是准确的,下面就来看看如何影响浏览器对资源加载的优先级。
浏览器是基于自身的启发式算法,会对资源的重要性进行判断,来划分优先级,通常从低到高分为Lowest、Low、High、Highest等。比如在head标签中,CSS文件通常具有最高的优先级Hightest,其次是script标签所请求的脚本文件,当script带有defer或async的异步属性时,其优先级就会降低到Low。可以通过浏览器控制台查看资源的优先级(priority优先级选项默认不显示,可以在开发者工具网络面板中右键点击列标题来启用优先级列):
通过浏览器的控制台就看到了不同资源的优先级情况。下面就来看看如果修改资源加载的优先级。
当页面的资源对用户来说比较重要,又被默认分配为较低优先级时,就可以使用资源的预处理或预连接,如果仅需要浏览器处理完一些任务之后,再去提取某些资源,就可以使用资源的欲提取。
(1)预加载
预加载应该是我们常听说的,可以使用<link ref="preload">
来告诉浏览器当前指定的资源应该具有更高的优先级,需要尽快开始加载资源:
<link ref="preload" as="script" href="important.js"> 复制代码
这里我们给link标签指定了一个as属性,它会告诉浏览器所要加载的资源的类型,当前需要加载的资源必须是这个指定类型的资源,不然不会进行预加载。需要注意的是,<link ref="preload">
是浏览器的强制性指令,preload后浏览器就必定去预加载相应的资源。使用时需要仔细测试,确保不会因为使用它而意外导致资源加载2次。
字体资源的预加载就是一个很好的例子,当使用非系统字体时,需要引入字体文件,字体文件通常都位于页面加载的CSS文件的末尾,为了减少用户等待站点文本内容的时间,以及避免系统字体与样式中定义的字体之间应用时的闪烁,可以在HTML中使用<link rel ="preload">
让浏览器知道样式文件中需要加载的字体资源:
<link ref="preload" as="font" crossorign="crossorign" type="font/woff2" href="font.woff2"> 复制代码
需要注意,这里的crossorign属性很重要,如果缺失,浏览器将忽略预加载的字体,并发起一个新的请求。因为浏览器使用匿名请求加载字体,只有使用crossorigin
属性可以使预加载请求匿名。
(2)预连接
我们知道,在较慢的网络环境下建立网络连接是非常耗时的,如果想建立安全连接将更加好事(例如HTTPS连接)。其原因主要是整个过程涉及到了DNS解析、重定向、三次握手过程等。如果能提前完后才能上述操作,那么就能带来更好的用户体验,与此同时,由于建立连接的大部分时间是消耗在等待的时间上,这样也能有效的优化宽度的使用情况。这时我们就可以使用预连接:
<link ref="preconnect" href="https://juejin.cn/"> 复制代码
这里通过<link ref="preconnect">
指令,告诉浏览器当前页面将与站点之间建立连接,希望尽快启动该过程。虽然这么做成本很低,但是会消耗抱回的CPU的时间,特别是在简历HTTPS安全连接时,如果建立好连接的10s之内没有使用该连接,浏览器就会关闭该连接,那么之前所有准备的资源就都浪费了。
除此之外,还有一种和预连接相关的类型<link ref="dns-prefetch">
,也就是DNS预解析,它仅用来处理DNS查询。该属性在浏览器的支持度很高,并且可以明显缩短DNS的查询时间,所以被普遍使用。
流媒体资源的预连接就是一个很好的例子,对于不同来源的流媒体,我们希望在连接阶段节省一些时间但不一定立即开始获取内容。根据页面处理流内容的方式,可能需要等到脚本加载完毕并做好准备后才处理流。一旦准备加载资源,预连接可帮助我们缩短单次往返的等待时间。
(3)预提取
前面所说的预解析和预连接都是试图更快的获取关键的资源,而接下来要说的预提取则是利用机会让某些非关键资源提前获取。
预提取就是根据用户已发生的行为来判断接下来的预期行为,告诉浏览器稍后可能需要的资源,也就是当页面加载完成之后,且在宽带可用的情况下,这些资源将以lowest的优先级进行提取。
从上面的描述中可知,预提取最适合的场景就是为用户的下一步可能的操作做好必要的准备,比如在搜索框搜索内容时,可以预提取结果列表中首个内容的详情页,或者在使用搜索查询是,预提取搜索结果的下一页的内容。
2. 图片懒加载
(1)什么是懒加载
懒加载也叫做延迟加载、按需加载,指的是在长网页中延迟加载图片数据,是一种较好的网页性能优化的方式。在比较长的网页或应用中,如果图片很多,所有的图片都被加载出来,而用户只能看到可视窗口的那一部分图片数据,这样就浪费了性能。
使用图片懒加载就可以解决上述问题。在滚动屏幕之前,可视化区域之外的图片不会进行加载,在滚动屏幕时才加载。懒加载适用于图片较多,页面较长的页面场景中。
懒加载与预加载的区别: 一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。
- 懒加载:指的是在长网页中延迟加载图片的时机,当用户需要访问时,再去加载,这样可以提高网站的首屏加载速度,提升用户的体验,并且可以减少服务器的压力。它适用于图片很多,页面很长的电商网站的场景。懒加载的实现原理是,将页面上的图片的 src 属性设置为空字符串,将图片的真实路径保存在一个自定义属性中,当页面滚动的时候,进行判断,如果图片进入页面可视区域内,则从自定义属性中取出真实路径赋值给图片的 src 属性,以此来实现图片的延迟加载。
- 预加载: 指的是将所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源。通过预加载能够减少用户的等待时间,提高用户的体验。我了解的预加载的最常用的方式是使用 js 中的 image 对象,通过为 image 对象来设置 scr 属性,来实现图片的预加载。
使用懒加载的好处:
- 减少无用资源的加载:使用懒加载明显减少了服务器的压力和流量,同时也减小了浏览器的负担;
- 提升用户体验: 如果同时加载较多图片,可能需要等待的时间较长,这样影响了用户体验,而使用懒加载就能大大的提高用户体验;
- 防止加载过多图片而影响其他资源文件的加载 :会影响网站应用的正常使用。
(2)传统方式实现
图片的加载是由src
引起的,当对src
赋值时,浏览器就会请求图片资源。根据这个原理,可以使用HTML5 的data-xxx
属性来储存图片的路径,在需要加载图片时,将data-xxx
中图片的路径赋值给src
,这样就实现了图片的按需加载,即懒加载。
注意:data-xxx
中的xxx
可以自定义,这里我们使用data-src
来定义。
懒加载的实现重点在于确定用户需要加载哪张图片。在浏览器中,可视区域内的资源就是用户需要的资源。所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可。这里使用 JavaScript 来实现懒加载。
相关知识点:
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> 复制代码
图片在进行懒加载时,需要不断监听scroll事件,然后判断图片是否已经在可视区域中,如果已经在可视区域就进行加载,如果没有则无需进行拉取。我们知道,scroll这类事件会被频繁触发,对性能的影响很大。那么针对这个scroll事件,可以使用节流函数包一下,让它隔一段时间再去触发,避免多余性能消耗,代码如下:
const imgLazyLoad = throttle(() => console.log('懒加载操作'), 1000) document.addEventListener('scroll', imgLazyLoad) 复制代码
用封装好的throttle去包装好懒加载操作,这样用户在频繁滚动滚动条的时候就不会产生因为频繁触发而带来的性能问题,这也是节流函数非常典型的一个应用。