懒加载(延迟加载):不用不加载

968 阅读6分钟

你不看,我就不加载。借助这个“偷懒”的思路,资源懒加载由此而生。

本文将讲解一些常见的懒加载优化。


重要的事情说三遍

  1. Web的性能优化无非从两个角度考虑:首屏加载性能、更新性能。

  2. Web的性能优化无非从两个角度考虑:首屏加载性能、更新性能。

  3. Web的性能优化无非从两个角度考虑:首屏加载性能、更新性能。


为什么要用懒加载

当今,网络传输的资源越来越大,随之也就越来越考验网络传输的速度和数据的展现方法。网络优化是一种角度,我们作为前端开发者不用太过于考虑,但是另外一种角度:优化展现方法,是我们必须掌握的一种优化手段,懒加载就是优化展现方法中的一种。

懒加载(延迟加载):对第一次渲染并不重要的资源来缩减关键渲染路径长度。

什么是关键渲染路径

通过MDN的解释: 关键渲染路径就是浏览器将HTML、CSS和JavaScript转换为屏幕上的像素所经历的步骤序列,优化关键渲染路径可以提高渲染性能。后面我们可以专门写一篇来讲解。

举几个懒加载栗子:

  1. 打开一个图片网站,可视窗口外的图片只会在用户将内容滑动到可视窗口时触发加载。
  2. 打开一个电商网站,具体的商品信息的静态资源只有在用户点击商品详情时被下载解析。

一些常见懒加载策略

对于HTML来说,它是浏览器最先请求到和处理的资源,我们比较难做性能上的优化。

当然这里有一些常见且很简单的SEO优化:

  1. meta标签写完整,比如name和description属性
  2. img的alt属性写完整
  3. 尽可能使用语义化标签等

CSS

CSS为什么被视为阻塞资源

CSS往往被浏览器视为阻塞资源,这是因为浏览器在处理HTML文件的时候当读取到<link> 标签的时候,往往会暂停解析后面的内容,直到CSS文件被完全下载和解析完成。这就造成了渲染阻塞。

针对阻塞资源(CSS)可做的优化

有一个思路便是:尽可能的把CSS文件变小, 加快CSS的送达。解决方法便是用媒体查询实现非阻塞渲染。

媒体查询优化

<link href="style.css" rel="stylesheet" media="all" />
<link href="portrait.css" rel="stylesheet" media="(orientation:portrait)" />
<link href="print.css" rel="stylesheet" media="print" />

上面的代码用了三个<link>标签来引入不同的CSS样式表,根据media的值来决定引入。

  1. style.cssmedia="all"意味着它适用于所有媒体类型和所有设备。
  2. portrait.css:这个样式表只在设备处于纵向模式时应用media="(orientation:portrait)",比如手机。
  3. print.cssmedia="print" 不言而喻,它是一个专门用于打印文档的演示表

媒体查询常见值

media 属性用于定义 CSS 样式表适用于哪种媒体类型或设备。它可以为不同的输出设备(如屏幕、打印机等)或不同的视口条件(如屏幕尺寸、设备方向等)指定不同的样式规则。

  1. all:适用于所有设备和媒体类型。
  2. print:仅适用于打印机和文档打印预览模式。
  3. screen:适用于彩色电脑屏幕。
  4. speech:适用于语音合成器等将页面朗读给用户听的设备。

除了媒体类型的属性值之外,还可以用媒体特性:

  1. width / height:基于视口的宽度和高度应用样式。
  2. min-width / max-width:基于视口宽度的最小值或最大值应用样式。
  3. orientation:基于设备的方向(横向或纵向)应用样式。
  4. resolution:基于设备的分辨率(如dpi或dpcm)应用样式。
  5. aspect-ratio:基于视口的宽高比应用样式。
  6. color:基于设备是否支持颜色以及颜色位数应用样式。
<link href="example.css" rel="stylesheet" media="(min-width: 768px) and (orientation: landscape)" />

关于CSS的优化可以有很多地方,我们暂且只讨论在懒加载上的优化。后期会出相关文章。

24/6/18更文:CSS还能做性能优化? - 掘金

JavaScript

type="module"

可以给Js脚本设置 type="module" ,这个脚本标签的作用就是把当前Js脚本当成一个JavaScript模块,它在默认情况下会被延迟加载。

<script src="./js/loading.js" type="module"></script>

defer && async

同样,<script>标签也可以用两个关键字来决定脚本文件的加载和执行。

defer

相当于替代了DOMContentLoaded ,告诉浏览器在DOM树构建完成和Render树渲染完成前执行脚本文件。

async

它会告诉浏览器,立即下载和执行Js脚本文件

但是async会导致一些问题:他不会等待DOM完全渲染完成,下载完就执行,这就导致了执行顺序的不确定性,如果有多个async脚本,就会导致顺序错乱,从而引发一些其他问题。

使用场景:外部脚本库,比如第三方的广告代码。。。。就是利用他的不确定性让这些脚本可以在页面加载的任何时候执行。

字体文件

笔者最近在做一个小项目,由于字体包设计问题(文件大小和上下空间位置等)导致首次加载时,字体会先失去设置的样式,然后闪一下变成设置的样式。虽然只在首次加载的时候出现,但是体验十分不好。

我们先来了解字体的渲染流程:在默认情况下,字体的请求会延迟到构造渲染树(DOM树+CSSOM树==渲染树)之前,这会导致文本渲染延迟加载。

优化方案

preload属性

其实就是设置一个<link>标签,让其带上 preload的 属性值。

<link rel="preload" href="./font/demoFont.ttf" as="font" type="font/ttf" crossorigin="anonymous">
<link rel="stylesheet" href="./style/loading.css">

<link rel="preload"> 是一个 HTML 指令,浏览器读取到的时候会预加载要用到的指定资源。从这一方面优化字体加载。但是会有弊端,就是不预加载完不执行下面的操作。

font-display

font-display这个属性主要是控制在字体加载过程中文本的显示方式,特别是在处理网络字体或者字体文件很大的时候。能很好的解决字体被阻塞的闪烁或者样式突变等问题(笔者遇到的就是这个问题)。

在平常使用时通常把preloadfont-display结合使用

示例:

  1. preload预加载
<link rel="preload" href="./font/demoFont.ttf" as="font" type="font/ttf" crossorigin="anonymous">
  1. font-display保证实现稳定
 @font-face {
    font-family: 'demoFont';
    src: url('../font/demoFont.ttf') format('truetype');
    font-weight: 900;
    font-display: swap;
}

图片和iframe的优化

图片的懒加载大家都比较熟悉了,可以用多种方法。事实上,W3C早就针对图片加载问题在原生DOM上做了优化。

Loading属性

Loading属性可以定义当前元素的加载方式:lazy

<img src="demo.jpg" alt="demo.webp" loading="lazy" />
<iframe src="demo.html" title="demo.html" loading="lazy"></iframe>

loading属性设置为lazy时,浏览器推迟加载屏幕外的img/iframe,直到用户滚动到其附近。


参考资料

  1. 关键渲染路径 - Web 性能 | MDN
  2. 外部资源链接元素 - HTML(超文本标记语言) | MDN
  3. HTMLImageElement:complete 属性 - Web API | MDN
  4. 什么是 JavaScript? - 学习 Web 开发 | MDN