让网页既快速又稳定的方法——图片懒加载(LazyLoad)

前端代码交给浏览器后,浏览器会干什么?

第一步:下载html 标签,接着会在内存之中建立DOM树

第二步:下载css样式表,于是便开始渲染树

第三步:DOM树再加上CSS渲染树完成后就得到了页面

接着进行:JavaScript执行、事件处理、资源加载、页面交互等等

而这次主要介绍的是前三步浏览器渲染页面时的加载方式------懒加载

懒加载

懒加载是一种常用的编程技术,其核心思想是推迟对象的创建或数据的加载直到真正需要它们的时候。这种技术可以提高应用的启动速度,减少内存占用,并提高性能。

来看这么一段代码

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <img  src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_753139.jpg">
    <img  src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_336055.jpg">
    <img   src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_753139.jpg">
    <img   src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_533951.jpg">
    <img   src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_322707.jpg">
    <img  src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_430418.jpg">
    <img src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_186979.jpg">
    <img  src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_534962.jpg">
    <img  src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_345749.jpg">
    <img  src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_979955.jpg">
</body>
</html>

会不会不经思考,这些图片会在进入页面的同一时间生成,那么如果这个页面带有很多很多张图片或者链接和程序,这个浏览器会不会需要加载很多时间呢?那么用户的体验感肯定非常不好

  • JS是单线程的
  • 而浏览器是多线程的
  • 浏览器还会启动新的下载线程,比如img、link、script等等

因此为了避免浏览器加载"堵车",便可以使用到懒加载,滑到哪就开始加载哪里

开始实现懒加载

第一步、避免图片被直接加载

将图片的标签属性改为数据属性data-src

添加滚动事件

鼠标滚动触发loadImage函数

html 复制代码
<body>
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_753139.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_336055.jpg">
    <img   data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_753139.jpg">
    <img   data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_533951.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_322707.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_430418.jpg">
    <img data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_186979.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_534962.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_345749.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_979955.jpg">
    <script>
        const imgs = document.getElementsByTagName('img')//该函数通过document.getElementsByTagName方法获取了页面中所有<img>标签元素,并将其存储在imgs变量中。
        const num = imgs.length
        function loadImage(){
            console.log('haha');
        }
        window.addEventListener('scroll',loadImage);//鼠标滚动触发loadImage函数
    </script>
</body>

第二步、编写Javascript使图片加载

确定滑到了哪张图片的位置

  • 先获取整屏的高度screenHeight

  • 再获取滚动条当前滑动的距离scrollTop

  • 再计算图片距离屏幕顶部的距离offsetTop

  • 如果如果图片距离顶部的距离小于滚动条滚动的距离加上可视区域的高度,则加载出图片

js 复制代码
    <script>
        const imgs = document.getElementsByTagName('img')
        const num = imgs.length
        function loadImage(){
            console.log('haha');
            // 是否在可视区
            let screenHeight = document.documentElement.clientHeight//获取可视区域的高度,为一屏高度
            let scrollTop = document.documentElement.scrollTop// 获取滚动条滚动的距离
             || document.body.scrollTop //兼容性写法,不同浏览器的兼容性问题 ||表或者的意思
            for(let i = 0; i < num; i++){
                if (imgs[i].offsetTop < scrollTop + screenHeight)//如果图片距离顶部的距离小于滚动条滚动的距离加上可视区域的高度,则加载图片
                {
                    //console.log(imgs[i]);
                    //console.log(imgs[i].dataset.src);//数据属性 dataset.src
                    //console.log(imgs[i].dataset.src,imgs[i].dataset.price);
                    imgs[i].src = imgs[i].getAttribute('data-src')//获取data-src属性的值
                }
                }
            }
        

        window.addEventListener('scroll',loadImage);//鼠标滚动触发
    </script>

至此浏览器下载html 标签,并且在内存之中建立DOM树

第三步、下载css样式表开始渲染树

这里就简单的设置一下CSS代码

css 复制代码
*{
    margin: 0;
    padding: 0;
}
body{
    background-color: bisque;
}

img {
    display: block;
    margin-bottom: 50px;
    width: 400px;
    height: 400px;
}

这样整体效果就实现了 只不过还有存在一些问题需要解决

  1. 监听事件太敏感,滑动时事件次数过多会导致存在内存占用过高问题
  2. 在点击进入页面时,页面中间的图片并没有加载出来,只有在滑动后才生成图片
  3. 在加载完成所有图片后,监听事件依然存在

第四步、取消事件监听、显示初始页面

在加载完成所有图片后取消事件监听

for循环中添加window.removeEventListener取消事件监听

js 复制代码
            for(let i = 0; i < num; i++){
                if (imgs[i].offsetTop < scrollTop + screenHeight)//如果图片距离顶部的距离小于滚动条滚动的距离加上可视区域的高度,则加载图片
                {
                    //console.log(imgs[i]);
                    //console.log(imgs[i].dataset.src);//数据属性 dataset.src
                    //console.log(imgs[i].dataset.src,imgs[i].dataset.price);
                    imgs[i].src = imgs[i].getAttribute('data-src')//获取data-src属性的值
                    n = i + 1;
                    if(n == num){
                        //console.log('加载完毕');
                        window.removeEventListener('scroll',loadImage);//完成所有图片加载后,取消滚动事件监听
                }
                }
            }

解决在点击进入页面时,页面中间的图片并没有加载出来问题只需要在loadImage()函数前再声明提升一下loadImage()

第五步、防抖节流

为了解决监听事件太敏感,滑动时事件次数过多会导致存在内存占用过高问题

导入方法库`lodash

html 复制代码
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

使用了lodash库(通过_符号表示)中的throttle函数来创建一个新的函数throttleLayLoad。对原始loadImage函数的一个节流,限制loadImage函数的执行频率,无论loadImage函数被调用得多频繁,throttleLayLoad都会确保它至少每隔200毫秒才执行一次。

更改鼠标滚动触发的函数为新的函数throttleLayLoad

js 复制代码
        const throttleLayLoad = _.throttle(loadImage,200)
        window.addEventListener('scroll',throttleLayLoad);

总结

通过图片懒加载技术,我们不仅优化了网页的加载速度,还提升了用户体验,是现代网页开发中不可或缺的性能提升策略。随着技术的演进,懒加载也逐渐集成到各种前端框架和库中,使得实现更为便捷高效。

  • 提高性能:通过减少不必要的资源加载,可以提高应用的响应速度和性能。
  • 节省资源:减少内存和带宽的使用,特别是在资源受限的环境中。
  • 提升用户体验:用户可以更快地看到他们需要的内容,而不是等待所有内容一次性加载完成。

(附上完整代码)

html 复制代码
<!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">
    <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

</head>
<body>
    <img  data-price="20" data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_753139.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_336055.jpg">
    <img   data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_753139.jpg">
    <img   data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629428917_533951.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_322707.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_430418.jpg">
    <img data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_186979.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_534962.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_345749.jpg">
    <img  data-src="https://img.3dmgame.com/uploads/images/news/20210820/1629429058_979955.jpg">
    <script>
        const imgs = document.getElementsByTagName('img')
        const num = imgs.length
        loadImage()
        function loadImage(){
            console.log('haha');
            // 是否在可视区
            let screenHeight = document.documentElement.clientHeight//获取可视区域的高度,为一屏高度
            let scrollTop = document.documentElement.scrollTop// 获取滚动条滚动的距离
             || document.body.scrollTop //兼容性写法,不同浏览器的兼容性问题 ||表或者的意思
            let n = 0
            for(let i = 0; i < num; i++){
                if (imgs[i].offsetTop < scrollTop + screenHeight)//如果图片距离顶部的距离小于滚动条滚动的距离加上可视区域的高度,则加载图片
                {
                    //console.log(imgs[i]);
                    //console.log(imgs[i].dataset.src);//数据属性 dataset.src
                    //console.log(imgs[i].dataset.src,imgs[i].dataset.price);
                    imgs[i].src = imgs[i].getAttribute('data-src')//获取data-src属性的值
                    n = i + 1;
                    if(n == num){
                        //console.log('加载完毕');
                        window.removeEventListener('scroll',throttleLayLoad);//完成所有图片加载后,取消滚动事件监听
                }
                }
            }
        }
        const throttleLayLoad = _.throttle(loadImage,200)//节流函数
        window.addEventListener('scroll',throttleLayLoad);//鼠标滚动触发
    </script>
</body>
</html>

以上图片均出自:《黑神话:悟空》新官方截图、壁纸&原画 超美超惊艳_3DM单机 (3dmgame.com)

相关推荐
cs_dn_Jie23 分钟前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic1 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿1 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具2 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
qq_390161772 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test3 小时前
js下载excel示例demo
前端·javascript·excel
Yaml43 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事3 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶3 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo3 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx