使用惰性图像加载来提高Web项目的性能是一种流行的优化技术。 关键是图像是现代网站挤满的“大量”资源。 我们已经发布了有关此的内容。
在这里,您可以了解延迟加载为Walmart网站带来了什么,并了解如何在React项目中使用IntersectionObserver。
这是有关优化静态站点的文章。
这是有关使用浏览器工具实现延迟加载的最新资料。

今天,我们提请您注意一篇文章的翻译,其中以一个简单的网页为例描述了IntersectionObserver API的使用。 本材料供初学者使用。
什么是延迟加载图像?
在分析应用程序性能时,最重要的两个指标是:首次交互时间(交互时间)和资源消耗(资源消耗)。 他们将不可避免地要面对从事Web开发的人员。 另外,应用程序可能会出现问题,这不仅是因为它们需要很长时间才能准备工作或消耗太多资源。 但是,无论如何,尽早找到这些问题的根源并努力确保这些问题甚至不会出现是非常重要的。
在Web应用程序中使用惰性图像加载技术可最大程度地降低性能问题的风险。 即,如果我们从延迟加载对其对使页面处于工作状态的时间和资源消耗的影响的角度进行分析,我们将获得以下信息:
- 首次互动的时间。 这是Web应用程序需要加载并使界面进入适合用户使用状态的时间。 延迟加载(不仅涉及图像)还优化了应用程序的响应时间,这要归功于分离代码并仅加载特定页面所需的内容或特定时间所需的内容的技术。
- 资源消耗。 人类是不耐烦的人。 如果网站需要超过3秒的加载时间,则70%的用户会离开该网站。 Web应用程序不应加载太长时间。 延迟加载使您可以减少页面工作所需的资源量。 例如,这可能意味着某个项目的代码被分解为片段,这些片段仅在需要它们的页面上加载。 结果,站点性能提高并且系统资源消耗减少。
因此,延迟加载技术可加速应用程序,减少其下载和启动时间。 这是由于仅在需要时才加载资源这一事实而实现的。
延迟加载为Web项目带来了以下两个优点:
- 页面加载速度更快并可以正常运行。
- 最初加载页面时,您必须传输和处理较少的数据。
使用IntersectionObserver API延迟加载图像
如果您考虑网页的加载方式,那么很明显,没有必要下载用户不可见的图像或其他资源。 使用延迟加载时,页面可见区域中的图像将首先加载。 然后,随着用户滚动页面,将加载其他图像,这些图像将落入页面的可见区域。
考虑一个例子。
页面及其可见区域看一下上图。 在这里,您可以看到浏览器和加载到其中的网页。 图片
#IMG_1
和
#IMG_2
在页面范围内。 这意味着它们对于用户是可见的,并且位于屏幕上显示的浏览器窗口区域的边界之内。
当页面
#IMG_1
,
#IMG_2
,
#IMG_3
和
#IMG_4
被加载时,不能以理想的方式使用该页面。 用户只能看到
#IMG_3
和
#IMG_4
并且对他隐藏
#IMG_3
和
#IMG_4
。 如果您在加载页面时加载了第一张和第二张图片,但未下载第三张和第四张图片,则可能会对网站的性能产生积极影响。 即,我们正在谈论以下内容。 当用户滚动页面以使第三个图像可见时-它将加载。 如果滚动继续并且第四张图像变为可见,则它也会加载。
滚动页面并加载图像既然我们已经弄清楚了我们要如何处理图像,我们将自问如何找到页面的某个元素落入其可见区域。 现代的浏览器都有一个API,允许程序员找出页面的特定区域何时可见。 关于IntersectionObserver API。 它允许使用异步机制来组织元素监视,并在元素超出文档范围或跨越另一个元素边界的情况下接收通知。
为了配置图像的延迟加载,我们首先需要为将用于描述图像的元素准备模板代码。 这是:
<img class="lzy_img" src="lazy_img.jpg" data-src="real_img.jpg" />
该类使您可以将元素标识为将应用延迟加载的图像。
src
属性允许您在显示实际图像之前显示占位符图像。
data-src
存储实际图像的地址,当元素进入页面的可见区域时将加载该地址。
现在,让我们编写实现延迟加载的代码。 如前所述,我们将使用IntersectionObserver API来检测图像进入页面查看区域的时间。
首先,创建一个
IntersectionObserver
实例:
const imageObserver = new IntersectionObserver(...);
IntersectionObserver
构造函数接受带有两个参数的函数。 其中一个存储一个数组,该数组由需要监视的元素组成,另一个存储
IntersectionObserver
实例。 看起来像这样:
const imageObserver = new IntersectionObserver((entries, imgObserver) => { entries.forEach((entry) => {
功能代码检查以查看由
entries
数组
entries
表示的图像是否与视口相交。 如果是这种情况,则相应图像的
src
属性记录其
data-src
属性中的内容。
const imageObserver = new IntersectionObserver((entries, imgObserver) => { entries.forEach((entry) => { if(entry.isIntersecting) { const lazyImage = entry.target lazyImage.src = lazyImage.dataset.src } }) });
在这里,我们使用
if(entry.isIntersecting) {...}
条件检查元素是否跨越浏览器查看区域。 如果是这样,我们将
img
元素保存在
lazyImage
常量中。 然后,在其
src
属性中写入其
data-src
属性中的内容。 因此,将加载并显示其地址存储在
data-src
中的图像。 在浏览器中,看起来就像用实际图像替换了占位符图像
lazy_img.jpg
。
现在,我们需要使用
IntersectionObserver
实例的
.observe()
方法来开始监视我们感兴趣的元素:
imageObserver.observe(document.querySelectorAll('img.lzy_img'));
在这里,我们使用
document.querySelectorAll('img.lzy_img')
命令
document.querySelectorAll('img.lzy_img')
lzy_img
document.querySelectorAll('img.lzy_img')
选择所有带有
lzy_img
类的
img
元素,并将它们传递给
.observe()
方法。 收到元素列表后,他开始观察它们的过程。
为了测试该示例,我们首先初始化Node.js项目:
mkdir lzy_img cd lzy_img npm init -y
现在在
lzy_img
文件夹中创建
lzy_img
文件:
touch index.html
向其添加以下代码:
<html> <title>Lazy Load Images</title> <body> <div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_1.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_2.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_3.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_4.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_5.jpg" /> <hr /> </div> </div> <script> document.addEventListener("DOMContentLoaded", function() { const imageObserver = new IntersectionObserver((entries, imgObserver) => { entries.forEach((entry) => { if (entry.isIntersecting) { const lazyImage = entry.target console.log("lazy loading ", lazyImage) lazyImage.src = lazyImage.dataset.src } }) }); const arr = document.querySelectorAll('img.lzy_img') arr.forEach((v) => { imageObserver.observe(v); }) }) </script> </body> </html>
您可能会注意到这里描述了5张图像,其中在加载时显示了
lazy_img.jpg
占位符。 它们每个的
data-src
属性都包含有关真实图像的信息。 这是项目中使用的图像名称的列表:
lazy_img.jpg img_1.jpg img_2.jpg img_3.jpg img_4.jpg img_5.jpg
您需要通过将项目文件夹置于下图所示的视图中来自己创建所有这些图像。
项目文件夹在我的情况下,使用Windows Paint准备了
lazy_img.jpg
文件,而真实图像(
img_*.jpg
.jpg )则来自
Foto.com 。
请注意,用于创建
IntersectionObserver
实例的回调具有
console.log()
调用。 这将使我们能够学习执行操作以加载不同的图像。
现在,要提供
index.html
,我们使用
http-server
包:
npm i http-server
将
start
属性添加到
package.json
文件的
scripts
部分:
"scripts": { "start": "http-server ./" }
之后,在终端中执行
npm run start
命令。
现在打开浏览器并转到地址
127.0.0.1:8080
。 我们一开始的
index.html
页面将如下图所示。
没有真实图像的页面您可能会注意到,在应该显示真实图像的位置,现在仅显示占位符。 在这里,我们从第一个图像位于查看区域的假设出发,因此浏览器开始下载它。 结果,页面现在将如下所示。
浏览器上传了第一张图片尚未上传其他图像。 他们尚未到达观看区域。
如果在观看控制台的同时滚动浏览页面,您会发现一个问题。 它包含以下事实:在查看窗口中滚动浏览同一图像时,浏览器会尝试多次下载该图像。
同一张图片的多次上传这根本不是我们所需要的。 这导致不必要的系统资源浪费,并降低项目性能。
为了解决此问题,我们需要从
IntersectionObserver
实例正在监视的元素列表中删除已为其加载实际图像的
img
元素。 我们还需要从该元素中删除
lzy_img
类。 修改后的回调函数代码如下所示:
<script> document.addEventListener("DOMContentLoaded", function() { const imageObserver = new IntersectionObserver((entries, imgObserver) => { entries.forEach((entry) => { if (entry.isIntersecting) { const lazyImage = entry.target console.log("lazy loading ", lazyImage) lazyImage.src = lazyImage.dataset.src lazyImage.classList.remove("lzy_img"); imgObserver.unobserve(lazyImage); } }) }); const arr = document.querySelectorAll('img.lzy_img') arr.forEach((v) => { imageObserver.observe(v); }) }) </script>
加载相应的
img
元素的真实图像后,将
lzy_img
其
lzy_img
类,并将该元素从
IntersectionObserver
观察的元素列表中排除。
这是示例代码:
<html> <title>Lazy Load Images</title> <body> <div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_1.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_2.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_3.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_4.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_5.jpg" /> <hr /> </div> </div> <script> document.addEventListener("DOMContentLoaded", function() { const imageObserver = new IntersectionObserver((entries, imgObserver) => { entries.forEach((entry) => { if (entry.isIntersecting) { const lazyImage = entry.target console.log("lazy loading ", lazyImage) lazyImage.src = lazyImage.dataset.src lazyImage.classList.remove("lzy_img"); imgObserver.unobserve(lazyImage); } }) }); const arr = document.querySelectorAll('img.lzy_img') arr.forEach((v) => { imageObserver.observe(v); }) }) </script> </body> </html>
总结
我们研究了图像延迟加载系统实现的最简单示例。 但是IntersectionObserver允许您创建非常复杂和懒惰的加载方案。 如果您对此主题感兴趣,建议您查看材料开头提到的出版物并阅读
文档 。
亲爱的读者们! 在实施惰性图像加载系统后,您是否有任何改善网站性能的示例?
