谈谈面试常考题:懒加载,防抖,节流(方法实现详解)

news2025/1/12 9:59:16

前言

最近在学习中确实收获了挺多东西,其中我觉得有必要拿来进行分享一下的就是懒加载了,还有相关的防抖和节流。因为在浏览器中这些都是属于很常见的性能优化,面试也是常考题。话不多说,速度发车。

什么是懒加载?懒加载实现了什么效果?

image.png

引言

像上图中的百度图片,有成千上万的图片,但是每个图片都是通过网络请求进行拿到。虽然是异步进行但是同时进行大量图片的请求,整个页面的渲染以及网络的请求资源的下载将会变得非常缓慢,影响用户观感体验。这对于前端网站来说是十分致命的缺陷。

在当今互联网时代,用户体验已成为衡量网站质量的重要指标之一。随着网页内容的日益丰富,特别是图片资源的大量使用,如何高效且快速地展示页面成为了前端开发中不可忽视的挑战。其中,“图片懒加载”技术便是解决这一问题的有效手段,它不仅能够提升页面加载速度,还能显著改善用户体验。

懒加载到底做了什么?

简单来说其实懒加载做的事情就是只加载用户屏幕目前所需要的图片,这里可能不是特别准确,但是大致意思就是加载目前用户屏幕所展示的图片其他的图片不进行加载,只有当用户滑动页面的时候,其他图片进行判断加载(图片出现在用户屏幕中则进行加载

这里提一嘴,只要浏览器已经加载过的图片就会加入到缓存中,浏览器可以直接从缓存中加载图片,而不是每次都重新发起网络请求。

懒加载原理是什么呢?为什么懒加载能控制图片的加载呢?

这里就不得不聊聊图片的特性了,其实只要图片具有src属性,浏览器就会对该地址进行网络请求下载资源。懒加载就是通过判断加载(前面提过)然后给图片进行src赋值,浏览器就会自动发送网络请求给资源地址进行下载。

懒加载实例和实现讲解

其实懒加载就是两点需要注意

  1. 如何控制img属性src赋值,并且图片地址存放在哪
  2. 什么时候进行加载什么时候不进行加载

关于第一点我的实现是使用自定义属性data-srcdata-为前缀的属性是HTML5引入的一个特性,允许开发者在HTML元素上嵌入自定义的数据属性。这类属性为非标准的属性,提供了存储与元素相关的元数据的方式,而不会影响到HTML的语义结构。在JavaScript中,可以通过元素的dataset属性轻松访问这些自定义数据属性。
这样我们就可以先使用data-src存储图片的资源地址,等到图片应当加载的时候,再进行src的赋值。

第二点我通过画图来解释

image.png

代码实现详解

实现步骤主要分为以下几点:

  • 监听鼠标滚轮事件,因为只有鼠标进行滚动之后新的图片才有可能出现在屏幕中,所以这里我们进行鼠标滚轮监听,只要鼠标滚动进行了滚动我们就执行图片加载方法进行判断。

  • 图片什么时候加载,主要需要做两件事情,第一件事情就是,判断图片是否进入到了屏幕中,这里我用的是
    offsetTop属性,offsetTop 是一个JavaScript DOM属性,用于获取一个元素相对于其最近的具有定位(positioned)的父元素顶部的距离。如果元素的所有祖先元素都没有定位(默认的 position: static),那么 offsetTop 会返回元素相对于整个文档顶部的距离。


    这里只需要判断图片的offsetTop属性(距离文档顶部的距离)是否 <= 滚轮已经滚动的距离scrollTop+屏幕高度clientHeight。让我画个图- ̗̀(๑ᵔ⌔ᵔ๑)

image.png

第二件事情就是通过dataset对象属性拿到自定义属性进行src的赋值,这一步知道dataset后就非常简单。

下面是我的实例代码,大家可以直接复制然后使用。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./common.css">
</head>

<body>
    <img data-price="20" data-src="https://www.toopic.cn/public/uploads/image/20200407/20200407210607_94155.jpg" />
    <img data-src="https://www.toopic.cn/public/uploads/image/20200408/20200408214128_24416.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/small/1704296749480170429674998.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/small/1695608930939169560893045.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/small/1642755454773164275545428.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/image/20200411/20200411125828_78760.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/image/20200409/20200409221455_72056.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/image/20200407/20200407213848_17992.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/image/20200405/20200405223436_89821.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/image/20200411/20200411125228_17646.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/image/20200407/20200407205944_99274.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/image/20200411/20200411125355_54192.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/image/20200404/20200404183643_27556.jpg">
    <img data-src="https://www.toopic.cn/public/uploads/image/20200407/20200407213757_91609.jpg">

</body>
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>
    const imgs = document.querySelectorAll('img');
    const num = imgs.length;
    const screenHeight = document.documentElement.clientHeight;//一屏的高度
    let n = 0;
    document.addEventListener('DOMContentLoaded', () => {
        loadImage();
    })
    function loadImage() {
        console.log('1');
        // 是否在可视区?
        // 滚动条偏移量
        // 不同浏览器兼容性问题
        let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        // console.log(screenHeight);
        for (let i = n; i < num; i++) {
            if (imgs[i].offsetTop < (scrollTop + screenHeight)) {
                // console.log(imgs[i].dataset);
                //数据属性
                imgs[i].src = imgs[i].dataset.src;
                // imgs[i].src = imgs[i].getAttribute('data-src');
                n = i + 1;
                if (n === num) {
                    window.removeEventListener('scroll', throttleLayLoad);
                }
            }
        }
    }
    const throttleLayLoad = _.throttle(loadImage, 300);
    window.addEventListener('scroll', throttleLayLoad);
    loadImage();
</script>

</html>

防抖和节流

引言

其实防抖和节流非常相似,只是各自实现判断的条件不同。

首先我来介绍一下为什么需要防抖和节流,当你鼠标滚动的时候,触发监听事件的次数可能会有成百上千次相同的图片加载方法也会执行上千次,其实并不是每次滚动都需要加载图片的,因为一个图片的高度需要你滚一会儿才能滚完。所以我们只需要在滚动的一段时间内触发一次图片加载方法就可以了。

相同的是,
两个方法都是通过定时器进行指定时间内的图片加载。不同的如下:

  • 防抖:在一段时间内频繁触发的事件,只有在最后一次触发后的一段时间内没有再次触发,才会执行函数。
  • 节流:确保一个函数在规定时间内只执行一次,即使在这段时间内多次触发,也保持固定的执行频率。
防抖方法详解
function debounce(func, delay) {
        //定时器
        let timer = null;
        return function () {
         // 当前时间段还有定时任务(图片加载函数)正在等待执行,取消timer(定时函数)
        if (timer) clearTimeout(timer);
        // 重新进入新的时间等待或者是时间段内第一次触发,给timer重新赋值
        timer = setTimeout(function () {
                //图片加载函数
                imageLoad();
            }, 500)
        }
    }

这样子,只要我在一段时间之内一直滚动的话,触发的也只有最后一次滚动执行的定时任务(图片加载)

节流方法详解
function throttle(func, delay) {
        //定义一个定时器
        let timer = null;
        return function () {
      // 当前时间段内已经执行过一次滚轮事件了,触发了一次定时任务(图片加载),不再执行图片加载函数了
            if (timer) return;
            //只有函数执行完或者第一次执行则再次执行
            timer = setTimeout(function () {
                func();
                timer = null;
            }, delay)
        }
    }

规定一段时间内,只能执行一次图片加载,也就是定时任务(图片加载)期间不允许再次执行

结语

图片懒加载作为前端性能优化的一项重要策略,其核心在于平衡资源加载与用户体验之间的关系。通过深入理解浏览器的工作机制,合理利用数据属性和JavaScript监听事件,我们可以有效提升网页的加载速度和响应性。此外,掌握防抖与节流等高级技巧,更是优化前端逻辑、提升代码效率的关键。

喜欢的话就点个关注和赞吧!谢谢- ̗̀(๑ᵔ⌔ᵔ๑)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1854342.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于Pytorch转换为MindSpore的一点建议

一、事先准备 必须要对Mindspore有一些了解&#xff0c;因为这个框架确实有些和其它流程不一样的地方&#xff0c;比如算子计算、训练过程中的自动微分&#xff0c;所以这两个课程要好好过一遍&#xff0c;官网介绍文档最好也要过一遍 1、零基础Mindspore&#xff1a;https://…

pytest测试框架flaky插件重试失败用例

Pytest提供了丰富的插件来扩展其功能&#xff0c;本章介绍下插件flaky &#xff0c;用于在测试用例失败时自动重新运行这些测试用例。与前面文章介绍的插件pytest-rerunfailures功能有些类似&#xff0c;但是功能上不如pytest-rerunfailures插件丰富。 flaky官方并没有明确pyt…

微软搁置水下数据中心项目——项目纳蒂克相比陆地服务器故障更少

“我的团队努力了&#xff0c;并且成功了&#xff0c;”COI负责人诺埃尔沃尔什说。 微软已悄然终止了始于2013年的水下数据中心&#xff08;UDC&#xff09;项目“纳蒂克”。该公司向DatacenterDynamics确认了这一消息&#xff0c;微软云运营与创新部门负责人诺埃尔沃尔什表示…

多路h265监控录放开发-(12)完成全部开始录制和全部停止录制代码

xviewer.h 新增 public: void StartRecord();//126 开始全部摄像头录制 void StopRecord();//126 停止全部摄像头录制 xviewer.cpp 新增 //视频录制 static vector<XCameraRecord*> records;//126void XViewer::StartRecord() //开始全部摄像头录制 126 {StopRecord…

vuex的深入学习[基于vuex3]----篇(二)

store对象的创建 store的传递图 创建语句索引 创建vuex的语句为new Vuex.Store({…})Vuex的入口文件是index.js,store是index.js导出的store类store类是store.js文件中定义的。 Store的构造函数constructor 判断vuex是否被注入&#xff0c;就是将vue挂载在window对象上&am…

[技术笔记] 元器件采购之Flash的国内、外厂商Top5

国外Top5 1、Micron&#xff08;镁光&#xff09;半导体 2、Toshiba&#xff08;东芝&#xff09; 3、Hynix&#xff08;海力士&#xff09; 4、Samsung&#xff08;三星&#xff09; 5、Intel&#xff08;因特尔&#xff09; 6、SanDisk&#xff08;闪迪&#xff09; 7…

瑞_MongoDB_MongoDB副本集

文章目录 1 MongoDB副本集-Replica Sets1.1 简介1.2 副本集的三个角色1.3 副本集架构目标1.4 副本集的创建1.4.1 创建主节点1.4.2 创建副本节点1.4.3 创建仲裁节点1.4.4 初始化配置副本集和主节点1.4.5 查看副本集的配置内容 rs.conf()1.4.6 查看副本集状态1.4.7 添加副本从节点…

1.4 Kettle 数据同步工具详细教程

工具介绍 一、概述 Kettle&#xff0c;又名 Pentaho Data Integration&#xff08;PDI&#xff09;&#xff0c;是一个开源的数据集成工具&#xff0c;最初由 Pentaho 公司开发。它能够从多种数据源提取、转换并加载&#xff08;ETL&#xff09;数据&#xff0c;适用于数据仓…

2023-2024 学年第二学期小学数学六年级期末质量检测模拟(制作:王胤皓)(90分钟)

word效果预览&#xff1a; 一、我会填 1. 1.\hspace{0.5em} 1. 一个多位数&#xff0c;亿位上是次小的素数&#xff0c;千位上是最小的质数的立方&#xff0c;十万位是 10 10 10 和 15 15 15 的最大公约数&#xff0c;万位是最小的合数&#xff0c;十位上的数既不是质数也…

(Amazing!) 通过 vfox 在 Windows 上安装管理多个 Erlang/OTP 和 Elixir 的版本

大概一个多月前, 我写了篇关于如何使用跨平台版本管理工具 vfox 在 Linux 系统下安装管理多个 Erlang/OTP 版本的文章 -> 通过 vfox 安装管理多版本 Erlang 和 Elixir. 文章使用的示范操作系统是 Ubuntu 20.04 Linux 操作系统. 最近 vfox-erlang 和 vfox-elixir 插件的最新…

理解 iOS 开发中的 NS_ENUM 和 NS_OPTIONS

在开发 iOS 应用程序时&#xff0c;理解 NS_ENUM 和 NS_OPTIONS 的使用至关重要&#xff0c;因为它们在定义和管理枚举和选项方面起着重要作用。在本文中&#xff0c;我们将深入探讨 NS_ENUM 和 NS_OPTIONS 之间的区别、使用场景以及如何有效地实现它们。 NS_ENUM NS_ENUM 用…

Python - 调用函数时检查参数的类型是否合规

前言 阅读本文大概需要3分钟 说明 在python中&#xff0c;即使加入了类型注解&#xff0c;使用注解之外的类型也是不报错的 def test(uid: int):print(uid)test("999")但是我就想要类型不对就直接报错确实可以另辟蹊径&#xff0c;实现报错&#xff0c;似乎有强…

网络编程篇:HTTP协议

一.预备知识 在客户端访问服务端时&#xff0c;要用ipport&#xff0c;但是在日常用户访问服务端的时候&#xff0c;并不会直接使用ip&#xff0c;而是使用域名&#xff0c;比如&#xff1a;百度(www.baidu,com)。 …

【机器学习】音乐大模型的深入探讨——当机器有了创意,是机遇还是灾难?

&#x1f440;国内外音乐大模型基本情况&#x1f440; ♥概述♥ ✈✈✈如FreeCompose、一术科技等&#xff0c;这些企业专注于开发人工智能驱动的语音、音效和音乐生成工具&#xff0c;致力于利用核心技术驱动文化产业升级。虽然具体公司未明确提及&#xff0c;但可以预见的是…

MFC学习--CListCtrl复选框以及选择

如何展示复选框 //LVS_EX_CHECKBOXES每一行的最前面带个复选框//LVS_EX_FULLROWSELECT整行选中//LVS_EX_GRIDLINES网格线//LVS_EX_HEADERDRAGDROP列表头可以拖动m_listctl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_GRIDLINES); 全选&#xff0c;全…

.hmallox勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复

导言&#xff1a; 在当今数字化时代&#xff0c;勒索病毒已经成为网络安全的一大威胁&#xff0c;其中包括了最近出现的.hmallox勒索病毒。这类恶意软件不仅能够对计算机系统进行加密&#xff0c;还会要求用户支付赎金以换取解密密钥&#xff0c;给个人用户和企业带来了严重的…

八大排序之希尔排序

一、概念及其介绍 希尔排序(Shell Sort)是插入排序的一种&#xff0c;它是针对直接插入排序算法的改进。 希尔排序又称缩小增量排序&#xff0c;因 DL.Shell 于 1959 年提出而得名。 它通过比较相距一定间隔的元素来进行&#xff0c;各趟比较所用的距离随着算法的进行而减小…

分类接口开发

文章目录 1.查询所有一级分类1.sun-club-application-controller 控制层1.SubjectCategoryController.java 定义基础的queryPrimaryCategory&#xff0c;调用领域层 2.sun-club-domain 领域层1.SubjectCategoryDomainService.java2.SubjectCategoryConverter.java3.SubjectCate…

PINN解偏微分方程实例4

PINN解偏微分方程实例4 一、正问题1. Diffusion equation2. Burgers’ equation3. Allen–Cahn equation4. Wave equation 二、反问题1. Burgers’ equation3. 部分代码示例 本文使用 PINN解偏微分方程实例1中展示的代码求解了以四个具体的偏微分方程&#xff0c;包括Diffusio…

编程精粹—— Microsoft 编写优质无错 C 程序秘诀 07:编码中的假象

这是一本老书&#xff0c;作者 Steve Maguire 在微软工作期间写了这本书&#xff0c;英文版于 1993 年发布。2013 年推出了 20 周年纪念第二版。我们看到的标题是中译版名字&#xff0c;英文版的名字是《Writing Clean Code ─── Microsoft’s Techniques for Developing》&a…