前端性能优化总结/懒加载、函数节流、优化dom操作、雪碧图、合并文件

1.减少 HTTP 请求数量
在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信。浏览器与服务器需要经过三次握手,每次握手需要花费大量时间。而且不同浏览器对资源文件并发请求数量有限(不同浏览器允许并发数),一旦 HTTP 请求数量达到一定数量,资源请求就存在等待状态,这是很致命的,因此减少 HTTP 的请求数量可以很大程度上对网站性能进行优化。

(1)懒加载
https://yq.aliyun.com/articles/255157
什么是懒加载
懒加载也叫延迟加载,指的是在长网页中延迟加载图像,是一种很好优化网页性能的方式。用户滚动到它们之前,可视区域外的图像不会加载。这与图像预加载相反,在长网页上使用延迟加载将使网页加载更快。在某些情况下,它还可以帮助减少服务器负载。常适用图片很多,页面很长的电商网站场景中。

为什么要用懒加载
能提升用户的体验,不妨设想下,用户打开像手机淘宝长页面的时候,如果页面上所有的图片都需要加载,由于图片数目较大,等待时间很长,用户难免会心生抱怨,这就严重影响用户体验。
减少无效资源的加载,这样能明显减少了服务器的压力和流量,也能够减小浏览器的负担。
防止并发加载的资源过多会阻塞js的加载,影响网站的正常使用。
懒加载的原理
首先将页面上的图片的 src 属性设为空字符串,而图片的真实路径则设置在data-original属性中, 当页面滚动的时候需要去监听scroll事件,在scroll事件的回调中,判断我们的懒加载的图片是否进入可视区域,如果图片在可视区内将图片的 src 属性设置为data-original 的值,这样就可以实现延迟加载。

图片懒加载

http请求
如果你学过计算机网络你就会知道,我们请求一个带有n张图片的html文件实际上会发送n+1次请求,因为在浏览器解析html的时候遇到了src,就会请求src后面的内容。

设想一下如果我们的页面有1000000张图片,那么如果等待这些图片响应成功并加载完时延是非常大的,而且图片的加载是同步的,加载时会阻塞浏览器继续向下解析,用户体验非常差。

那么我们可不可以让图片按需加载呢?当图片出现在可视区的时候再加载它而不是一开始就加载完全部图片。

template:

<div @scroll="lazyLoad" ref="lazy">
    <img v-for="(src, index) in imgs" src="##" :dataSrc="src" :key="index">
    <!--more img-->
</div>
改变图片src
监听最外层div的滚动事件,触发滚动时遍历图片检测图片位置,若在可视区内则显示

复制代码
loadImg() {
    var img = this.$refs.lazy.getElementsByClassName("lazyImg"); 
    // 已滚动高度+可视区高度
    var top = this.$refs.lazy.scrollTop + this.$refs.lazy.clientHeight;
    
    for(var i = 0; i < img.length; i++) {
        if(img[i].offsetTop <= top) {  // 在可视区内则显示图片
            img[i].src = img[i].getAttribute("datasrc");
        }
    }
},
lazyLoad() { 
    this.loadImg();
}

以上就实现了一个图片懒加载

一个严重的问题:滚动过程中会不断触发lazyLoad对图片做一个遍历并判断,那么就会做无数次for循环,更可怕的是,修改一次src会发送一个请求,在滚动的时候我们的for循环每次都从头判断并修改src请求图片,那么请求次数可想而知。

函数防抖
如果在滚动过程中不断触发遍历并判断图片是否在可视区的监听事件,会耗费很大的性能,这里采用函数防抖:当用户停止滚动时统一遍历判断图片位置

debounce(fn) {
    // 函数防抖:用户停止操作之后触发
    clearTimeout(this.timer);
    this.timer = setTimeout(() => {
        fn();
    }, 1000);
}

我们可以将加载图片的方法放在debounce中

lazyLoad() {
    this.debounce(this.loadImg);
}

这样当用户滚动页面时,松开手才会执行loadImg来遍历判断图片位置。

又出现了一个问题:如果用户在滚动时从页面底部上拉到顶部一直没有松手,那么在这期间都不会执行loadImg,这意味着页面的图片都不会显示,非常影响用户体验

防抖优化
我们规定,若用户上拉高度大于500px那么就自动加载一次可视区内图片,这里我们用oldScrollTop记录上次上拉高度

lazyLoad() {
    // 如果上拉距离大于500px则自动加载
    if(this.$refs.lazy.scrollTop - this.oldScrollTop > 500) {
        this.loadImg();
        this.oldScrollTop = this.$refs.lazy.scrollTop; // 更新oldScrollTop
    } else {  // 如果向下拉但小于500px则防抖加载
        this.debounce(this.loadImg);
    }
}

下拉优化
当用户下拉的时候我们并不需要执行lazyLoad,因为我们之前的图片已经加载过了,所以可以修改一下lazyLoad

lazyLoad() {
    // 如果上拉距离大于500px则自动加载
    if(this.$refs.lazy.scrollTop - this.oldScrollTop > 500) {
        this.loadImg();
        this.oldScrollTop = this.$refs.lazy.scrollTop;
    } else if(this.$refs.lazy.scrollTop - this.oldScrollTop < 0) {  // 如果向下拉则不做操作
        return ;
    } else {  // 如果向下拉但小于500px则防抖加载
        this.debounce(this.loadImg);
    }
}

减少遍历个数
最重要的优化已经做完了,但是还可以从一些小细节更加优化一下,我们的loadImg方法中每次都是从0号下标开始遍历检查图片,但是在用户上拉操作之后一部分图片已经被加载了,就不需要再次去检查了。

我们可以用一个变量len记录上一次被加载后的最后一个图片,然后修改一下loadImg

 loadImg() {
    var img = this.getImages(); 
    var top = this.$refs.lazy.scrollTop + window.screen.height;
    
    // 从len开始检查
    for(var i = this.len; i < img.length; i++) {
        if(img[i].offsetTop <= top) {
            img[i].src = img[i].getAttribute("datasrc");
            this.len = i;  // 更新len
        }
    }
}

懒加载和预加载

懒加载的原理:
图片预加载:就是在网页全部加载之前,提前加载图片,当用户需要查看时可直接从本地缓存中渲染,以提供给用户更好的体验,减少等待的时间。

图片懒加载(缓载):延迟加载图片或符合某些条件时才加载某些图片。


懒加载的实现:
HTML部分:


<div class="box">

        <h1>js懒加载</h1>

        <div class="box">

            <img src="" class="img" lazyload="true" data-original="http://pic.58pic.com/58pic/17/18/97/01U58PIC4Xr_1024.jpg">

            <img src="" class="img" lazyload="true" data-original="http://pic.58pic.com/58pic/17/18/97/01U58PIC4Xr_1024.jpg">

            <img src="" class="img" lazyload="true" data-original="http://pic.58pic.com/58pic/17/18/97/01U58PIC4Xr_1024.jpg">

            <img src="" class="img" lazyload="true" data-original="http://pic.58pic.com/58pic/17/18/97/01U58PIC4Xr_1024.jpg">

            <img src="" class="img" lazyload="true" data-original="http://pic.58pic.com/58pic/17/18/97/01U58PIC4Xr_1024.jpg">

            <img src="" class="img" lazyload="true" data-original="http://pic.58pic.com/58pic/17/18/97/01U58PIC4Xr_1024.jpg">

            <img src="" class="img" lazyload="true" data-original="http://pic.58pic.com/58pic/17/18/97/01U58PIC4Xr_1024.jpg">

            <img src="" class="img" lazyload="true" data-original="http://pic.58pic.com/58pic/17/18/97/01U58PIC4Xr_1024.jpg">

            <img src="" class="img" lazyload="true" data-original="http://pic.58pic.com/58pic/17/18/97/01U58PIC4Xr_1024.jpg">



        </div>

    </div>



JS部分:
   window.onload = function () {

    //获取当前浏览器的视口高度

    var viewHeight = document.documentElement.clientHeight;

    //鼠标滚动回调

    function lazyload() {

        var img = document.getElementsByClassName('img'); //获取所有图片集合

        //遍历图片集合

        for (let item of img) {

            //获取图片距视口顶部的距离

            var imgHeight = item.getBoundingClientRect();

            //判断当图片出现在视口160px时把地址放到src中,显示出图片

            if (imgHeight.top < (viewHeight - 200)) {

                item.src = item.getAttribute("data-original")

            }

        }

    }

    lazyload();    //页面加载时把当前视口中的图片加载进来

    document.addEventListener('scroll', lazyload);

}


预加载:
css部分:
*html{ 

margin:0; 

padding:0; 

border:0; 

} 

body{border:1px solid #f3f3f3; background:#fefefe} 

div#loading{ 

width:950px; 

height:265px; 

line-height:265px; 

overflow:hidden; 

position:relative; 

text-align:center; 

} 

div#loading p{ 

position:static; 

+position:absolute; 

top:50%; 

vertical-align:middle; 

} 

div#loading p img{ 

position:static; 

+position:relative; 

top:-50%;left:-50%; 

vertical-align:middle 

} 

HTML部分:

<div id="loading">

    <p><img src="" class="img" lazyload="true" data-original="http://pic.58pic.com/58pic/17/18/97/01U58PIC4Xr_1024.jpg"></p>

</div>

js部分:
 

var i=0; 

var c=3; 

var imgarr=new Array 

imgarr[0]="http://www.baidu.com/img/baidu_logo.gif"; 

imgarr[1]="http://img.baidu.com/img/logo-img.gif"; 

imgarr[2]="http://img.baidu.com/img/logo-zhidao.gif"; 

var Browser=new Object(); 

Browser.userAgent=window.navigator.userAgent.toLowerCase(); 

Browser.ie=/msie/.test(Browser.userAgent); 

Browser.Moz=/gecko/.test(Browser.userAgent); 

function SImage(url,callback) 

{ 

var img = new Image(); 

if(Browser.ie){ 

img.onreadystatechange =function(){ 

if(img.readyState=="complete"||img.readyState=="loaded"){ 

ii=i+1; 

callback(i); 

} 

} 

}else if(Browser.Moz){ 

img.onload=function(){ 

if(img.complete==true){ 

ii=i+1; 

callback(i); 

} 

} 

} 

img.src=url; 

} 

function icall(v) 

{ 

if(v

SImage(""+imgarr[v]+"",icall); 

} 

else if(v>=c){ 

i=0; 

//location.replace('banner.html');//这里写自己的动作吧, 

} 

} 

图片预加载与懒加载的区别:
两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预载则会增加服务器前端压力。

一、懒加载

1.概念:

访问页面时,先把img元素的背景图片src替换成一张占位图,这样只需请求一次,当图片出现在浏览器的可视区域内时,再设置图片的真实路径,显示图片。

2.优点:

页面长图片多时,在首次载入时一次性加载会耗费时间长,使用懒加载可以使页面加载速度快、减轻服务器的压力、节约流量。

3.步骤:

页面中的img元素,若没有src属性,浏览器就不会发出请求去下载图片,只有通过Javascript设置了图片路径,浏览器才会发送请求。

1)懒加载先在页面中把需要延迟加载的图片统一使用一张占位图进行占位,把真正的路径存在元素“data-url”属性里。

2)页面加载完成后,通过scrollTop判断图片是否在用户的视野,如果在,则将 data-url的值取出来存放到src中。

3)在滚轮事件中重复判断图片是否进入视中,如果在,则将data-url的值取出来存放到src中。

4.demo:

<style type="text/css"> 
img{ display: block; }
</style>
<body>
 <img src="" alt="">
 <img src="" alt="">
 <img src="" alt="">
 <img src="" alt="">
 <img src="" alt="">
</body>
<script type="text/javascript"> 
var pic=document.getElementsByTagName('img');
 arr=['img1.jpg','img2.jpg','img3.jpg','img4.jpg','img5.jpg'];
  for(var i=0;i<arr.length;i++){
   pic[i].setAttribute('src-data', arr[i]);
    }
     for(var i=0;i<4;i++){
      pic[i].setAttribute('src', pic[i].getAttribute('src-data'));
       }
     document.onmousewheel=function(){ 
    if(document.body.clientHeight+document.body.scrollTop>=
    pic[3].offsetTop+pic[3].offsetHeight){ 
    pic[4].setAttribute('src',pic[4].getAttribute('src-data'));
     } 
     }
 </script>
  1. 插件

成熟的懒加载插件,直接调用方法即可。 jquery.lazyload.js压缩版:jquery.lazyload.js

jquery.lazyload.js正常版:jquery.lazyload.js

如何使用

Lazy Load 依赖于 jQuery. 请将下列代码加入HTML的结尾,也就是

</body>

前:

<script type="text/javascript" src="jquery.js">
</script>
<script type="text/javascript" src="jquery.lazyload.js">
</script>

你必须改变图片的标签。图像的地址必须放在

data-original

属性上。给懒加载图像一个特定的class(例如:lazy)。这样你可以很容易地进行图像插件捆绑。代码如下:

<img class="lazy" alt="" width="640" height="480" data-original="img/example.jpg" />

$(function() { $("img.lazy").lazyload();});

这将使所有 class 为

lazy

的图片将被延迟加载.Demo:基本选项

TIPS:这里必须设置图片的

width

和

height

,否则插件可能无法正常工作。

设置临界点

默认情况下图片会出现在屏幕时加载. 如果你想提前加载图片, 可以设置

threshold

选项, 设置 threshold 为 200 令图片在距离屏幕 200 像素时提前加载.

$("img.lazy").lazyload({ threshold : 200});

设置事件来触发加载

你可以使用jQuery事件,例如

click

和

mouseover

。也可以使用自定义事件,如

sporty

、

foobar

默认情况下是要等到用户向下滚动并且图像出现在视口中时。只有当用户点击它们才加载图片:

$("img.lazy").lazyload({ event : "click"});

Demo:经过五秒钟的延迟后加载图片

使用特效

默认情况下,插件等待图像完全加载并调用

show()

。你可以使用任何你想要的效果。下面的代码使用

fadeIn

(淡入效果)。Demo:淡入效果

$("img.lazy").lazyload({ effect : "fadeIn"});

针对不启用JavaScript的情况

几乎所有浏览器的 JavaScript 都是激活的. 然而可能你仍希望能在不支持 JavaScript 的客户端展示真实图片. 当浏览器不支持 JavaScript 时优雅降级, 你可以将真实的图片片段在写

<noscript>

标签内.

<img class="lazy" data-original="img/example.jpg" width="640" heigh="480"><noscript><img src="img/example.jpg" width="640" heigh="480"></noscript>

可以通过 CSS 隐藏占位符.

.lazy { display: none;}

在支持 JavaScript 的浏览器中, 你必须在 DOM ready 时将占位符显示出来, 这可以在插件初始化的同时完成.

$("img.lazy").show().lazyload();

图片在容器里面

你可以将插件用在可滚动容器的图片上, 例如带滚动条的 DIV 元素. 你要做的只是将容器定义为 jQuery 对象并作为参数传到初始化方法里面.Demo:容器内水平滚动, 容器内垂直滚动

当图像不连续时

滚动页面的时候, Lazy Load 会循环为加载的图片. 在循环中检测图片是否在可视区域内. 默认情况下在找到第一张不在可见区域的图片时停止循环. 图片被认为是流式分布的, 图片在页面中的次序和 HTML 代码中次序相同. 但是在一些布局中, 这样的假设是不成立的. 不过你可以通过

failurelimit

选项来控制加载行为.

$("img.lazy").lazyload({ failure_limit : 10});

将 failurelimit 设为 10 ,令插件找到 10 个不在可见区域的图片时才停止搜索. 如果你有一个猥琐的布局, 请把这个参数设高一点.

加载隐藏的图片

可能在你的页面上埋藏可很多隐藏的图片. 比如插件用在对列表的筛选, 你可以不断地修改列表中各条目的显示状态. 为了提升性能, Lazy Load 默认忽略了隐藏图片. 如果你想要加载隐藏图片, 请将

skip_invisible

设为

false

$("img.lazy").lazyload({ skip_invisible : false});

二、预加载

1.概念:

提前加载图片,当用户需要查看时可直接从本地缓存中渲染。

2.优点:

图片预先加载到浏览器中,这对图片占据很大比例的网站来说十分有利,它保证了图片快速、无缝地发布,也可帮助用户在浏览网站内容时操作得到最快的反映。

3.实现方式

实现预载的方法非常多,比如:用CSS和JavaScript实现预加载;仅使用JavaScript实现预加载;使用Ajax实现预加载。

4.js预加载demo:

常用方法new Image(),设置其src来实现预载,再使用onload方法回调预载完成事件。只要浏览器把图片下载到本地,同样的src就会使用缓存。当Image下载完图片头后,会得到宽和高,因此可以在预载前得到图片的大小。

//要预加载的图片路径

三、预加载与懒加载对比

1.概念:

懒加载也叫延迟加载:JS图片延迟加载,延迟加载图片或符合某些条件时才加载某些图片。 预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。

2.区别:两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓加载甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

懒加载
什么是懒加载
懒加载也就是延迟加载;当访问一个页面时,先将img标签中的src链接设为同一张图片(这样就只需请求一次,俗称占位图),将其真正的图片地址存储在img标签的自定义属性中(比如data-src);当js监听到该图片元素进入可视窗口时,即将自定义属性中的地址存储到src属性中,达到懒加载的效果;这样做能防止页面一次性向服务器响应大量请求导致服务器响应慢页面卡顿或崩溃等问题

为什么要使用懒加载
懒加载对于图片较多页面很长的业务场景很适用,可以减少无效资源的加载

懒加载的实现步骤
1.首先,不要将图片地址放到src属性中,而是放到其它属性(data-src)中

2.页面加载完成后,根据scrollTop判断图片是否在用户的视野内,如果在,则将data-original属性中的值取出存放到src属性中

3.在滚动事件中重复判断图片是否进入视野;如果进入,则将data-original属性中的值取出存放到src属性中

代码实现:
既然懒加载的原理是基于判断元素是否出现在窗口可视范围内,首先我们写一个函数判断元素是否出现在可视范围内:

<script>
function isVisible($node){
    var winH = $(window).height(),
        scrollTop = $(window).scrollTop(),
        offSetTop = $(window).offSet().top;
    if (offSetTop < winH + scrollTop) {
        return true;
    } else {
        return false;
    }
}
</script>

再添加上浏览器的事件监听函数,让浏览器每次滚动就检查元素是否出现在窗口可视范围内:

<script>
$(window).on("scroll", function{
    if (isVisible($node)){
        console.log(true);
    }
})
</script>

现在我们要做的是,让元素只在第一次被检查到时打印true,之后就不再打印了

<script>
var hasShowed = false;
$(window).on("sroll",function{
    if (hasShowed) {
        return;
    } else {
        if (isVisible($node)) {
            hasShowed = !hasShowed;
            console.log(true);
        }
    }
})
</script>

这样我们就实现了懒加载

利用懒加载和AJAX,我们还可以实现无限滚动查看时间线/在滚动页面一段距离后出现回到顶部按钮的效果

懒加载的优点
显著的提高页面加载速度,又不下载多余的资源节省了流量;同时更少的图片并发请求数也可以减轻服务器的压力

懒加载插件
关于图片延时加载,网上有很多应用的例子以及插件;目前研究过的两个插件分别是jquery插件lazyload.js和原生js插件echo.js;二者的区别不用说,jquery插件使用的时候必须引入jquery才可以,且该插件功能强大,灵活性也高;而echo.js是用原生写的插件,代码少,不依赖其他库,拿起来就可以用,但能够实现的效果不如lazyload丰富强大,但基本的延时加载要求都能满足

jquery.lazyload.js
如何使用
延迟加载依赖于于jQuery,第一步引入文件:

<script src ="jQuery.js"></script>
<script src="jQuery.lazyload.js"></script>
接下来修改html的一些属性:图像的src地址暂时存储在自定义属性data-original中,然后给需要延时加载图像加上一个特定的类,类的名字由你自己决定,使用的时候统一类名即可;为这些图片绑定延时加载:

<img class="lazy" src="img/grey.gif" data-original="img/example.jpg"  width="640" heigh="480">
用的时候就像下面:

$("img.lazy").lazyload();
所有class为lazy的图片将被延迟加载

注意:必须设置图像的尺寸,宽度和高度属性或CSS,否则插件可能无法正常工作

参数设置
1.设置阈值

默认情况下图片在位于可视区域后才开始加载;如果想提前加载图片,可通过设置threshold的值来改变其显示的时间,设置threshold为200使图片在距离屏幕可见区域下方200像素时就开始加载

$("img.lazy").lazyload({
  threshold:200
});

2.事件触发加载

默认是scoll事件触发延时加载,即等到用户向下滚动至图片出现在屏幕可视区域时图片才能加载,但可以使用jQueryclick或mouseover等事件触发图片的加载,也可以使用自定义事件,实现只有当用户点击图片图片才能够加载时可以这样写:

$("img.lazy").lazyload({
    event : "click"
});

注意:你也可以使用这个技巧延迟图片加载,即加载前延迟5秒后再加载图片;就像下面这样(trigger()方法触发被选元素的指定事件类型):

$(function() {
    $("img.lazy").lazyload({
        event:"click"
    });
});
$(window).bind("load", function() {
    var timeout = setTimeout(function() {
        $("img.lazy").trigger("click") //trigger()方法触发被选元素的指定事件类型
    }, 5000);
});

3.使用特殊效果加载图片

插件默认使用show()方法显示图片;当然你可以使用任何你想用的特效来处理,例如使用fadeIn效果:

$("img.lazy").lazyload({ 
    effect : "fadeIn" //.effect()方法对一个元素应用了一个命名的动画 特效
});

4.为非JavaScript浏览器回退

<img class="lazy" src="img/grey.gif" data-original="img/example.jpg"  
width="640" heigh="480">
<noscript>
<img src="img/example.jpg" width="640" heigh="480">
</noscript>

可以通过CSS隐藏占位符

.lazy {
  display: none;
}

在支持JavaScript的浏览器中必须在DOM ready时将占位符显示出来,这可以在插件初始化的同时完成

$("img.lazy").show().lazyload();

这些都是可选的,但如果你希望插件平稳降级这些都是应该做的

5.图片内容器

可以将插件用在可滚动容器的图片上,例如带滚动条的DIV元素;将容器定义为jQuery对象并作为参数传到初始化方法里面

#container {
    height: 600px;
    overflow: scroll;
}
$("img.lazy").lazyload({         
     container: $("#container")
}); 

6.当图像并不是连续的

滚动页面时,Lazy Load会循环加载图片;在循环中检测图片是否在可视区域内,默认情况下在找到第一张不在可见区域的图片时停止循环;图片被认为是流式分布的,图片在页面中的次序和HTML代码中次序相同;但是在一些布局中,这样的假设是不成立的;不过你可以通过failurelimit选项来控制加载行为

$("img.lazy").lazyload({ 
    failure_limit : 10
}); 

将failurelimit设为10令插件找到10个不在可见区域的图片是才停止搜索

7.处理看不见图像

可能在你的页面上有很多隐藏的图片;为了提升性能,Lazy Load默认忽略了隐藏图片;如果想要加载隐藏图片,将skip_invisible设为 false:

$("img.lazy").lazyload({ 
    skip_invisible : false
}); 
echo.js
兼容性:Echo.js使用了HTML5的date属性,并且需要获取该属性的值,所以它并不兼容IE6/IE7

使用方法:

引入文件
<script src="js/echo.min.js"></script> 
HTML
<img src="images/blank.gif" alt="pic" data-echo="img/pic.jpg" width="640" height="480">
blank.gif用做默认图片,data-echo的属性值是图片的真实地址,同样最好给图片设置宽度和高度

JavaScript
echo.init({
    offset: 0,
    throttle: 0
});
参数说明
echo.js只有两个参数:offset和throttle

offset:设置图片在离可视区域下方在一定距离后开始被加载

throttle:设置图片延迟多少毫秒后加载

那么上面的代码的意思就是一旦图片进入可视区域就立即加载

预加载
什么是预加载
提前加载图片,当用户需要查看时可直接从本地缓存中渲染

为什么要使用预加载
图片预先加载到浏览器中,访问者可顺利地在网站上冲浪,并享受到极快的加载速度;这对图片占据很大比例的网站来说十分有利,保证了图片快速/无缝地发布,也可帮助用户在浏览网站内容时获得更好的用户体验

预加载的核心要点如下:

图片等静态资源在使用前提前请求;资源后续使用时可以从缓存中加载,提升用户体验;页面展示的依赖关系维护(必需的资源加载完才可以展示页面,防止白屏等)

实现预加载主要有三个方法:
用CSS和JavaScript实现预加载
实现预加载图片有很多方法,包括使用CSS/JavaScript/两者的各种组合,这些技术可根据不同设计场景设计出相应的解决方案,十分高效

1.单纯使用CSS,可容易/高效地预加载图片,代码如下:

#preload-01 { background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px; }  
#preload-02 { background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999px; }  
#preload-03 { background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999px; }

将这三个ID选择器应用到(X)HTML元素中,我们便可通过CSS的background属性将图片预加载到屏幕外的背景上;只要这些图片的路径保持不变,当它们在Web页面的其他地方被调用时,浏览器就会在渲染过程中使用预加载(缓存)的图片;简单/高效,不需要任何JavaScript

该方法虽然高效,但仍有改进余地;使用该法加载的图片会同页面的其他内容一起加载,增加了页面的整体加载时间;为了解决这个问题,我们增加了JS代码来推迟预加载的时间,直到页面加载完毕;代码如下:

function preloader() {  
    if (document.getElementById) {  
        document.getElementById("preload-01").style.background = "url(http://domain.tld/image-01.png) no-repeat -9999px -9999px";  
        document.getElementById("preload-02").style.background = "url(http://domain.tld/image-02.png) no-repeat -9999px -9999px";  
        document.getElementById("preload-03").style.background = "url(http://domain.tld/image-03.png) no-repeat -9999px -9999px";  
    }  
}  
function addLoadEvent(func) {  
    var oldonload = window.onload;  
    if (typeof window.onload != 'function') {  
        window.onload = func;  
    } else {  
        window.onload = function() {  
            if (oldonload) {  
                oldonload();  
            }  
            func();  
        }  
    }  
}  
addLoadEvent(preloader);

在脚本的第一部分,我们获取使用类选择器的元素并为其设置了background属性,以预加载不同的图片;脚本的第二部分,我们使用addLoadEvent()函数来延迟preloader()函数的加载时间,直到页面加载完毕;如果JavaScript无法在用户的浏览器中正常运行,会发生什么?很简单,图片不会被预加载,当页面调用图片时,正常显示即可

2.仅使用JavaScript实现预加载

上述方法有时确实很高效,但我们逐渐发现它在实际实现过程中会耗费太多时间;相反,我更喜欢使用纯JavaScript来实现图片的预加载;下面将提供两种这样的预加载方法,它们可以很漂亮地工作于所有现代浏览器之上

加载方法1:

只需简单编辑/加载所需要图片的路径与名称即可,很容易实现:

<div class="hidden">  
    <script type="text/javascript">   
            var images = new Array()  
            function preload() {  
                for (i = 0; i < preload.arguments.length; i++) {  
                    images[i] = new Image()  
                    images[i].src = preload.arguments[i]  
                }  
            }  
            preload(  
                "http://domain.tld/gallery/image-001.jpg",  
                "http://domain.tld/gallery/image-002.jpg",  
                "http://domain.tld/gallery/image-003.jpg"  
            )  
    </script>  
</div>

该方法尤其适用预加载大量的图片

加载方法2:

该方法与上面的方法类似,也可以预加载任意数量的图片;将下面的脚本添加入任何Web页中,根据程序指令进行编辑即可

<div class="hidden">  
    <script type="text/javascript"> 
            if (document.images) {  
                img1 = new Image();  
                img2 = new Image();  
                img3 = new Image();  
                img1.src = "http://domain.tld/path/to/image-001.gif";  
                img2.src = "http://domain.tld/path/to/image-002.gif";  
                img3.src = "http://domain.tld/path/to/image-003.gif";  
            }  
    </script>  
</div>

正如所见,每加载一个图片都需要创建一个变量,如"img1=new Image();",及图片源地址声明,如"img3.src=’…/path/to/image-003.gif’;";参考该模式,可根据需要加载任意多的图片;我们又对该方法进行了改进,将该脚本封装入一个函数中,并使用addLoadEvent()延迟预加载时间,直到页面加载完毕

function preloader() {  
    if (document.images) {  
        var img1 = new Image();  
        var img2 = new Image();  
        var img3 = new Image();  
        img1.src = "http://domain.tld/path/to/image-001.gif";  
        img2.src = "http://domain.tld/path/to/image-002.gif";  
        img3.src = "http://domain.tld/path/to/image-003.gif";  
    }  
}  
function addLoadEvent(func) {  
    var oldonload = window.onload;  
    if (typeof window.onload != 'function') {  
        window.onload = func;  
    } else {  
        window.onload = function() {  
            if (oldonload) {  
                oldonload();  
            }  
            func();  
        }  
    }  
}  
addLoadEvent(preloader);

3.使用Ajax实现预加载

上面所给出的方法似乎不够酷,那现在来看一个使用Ajax实现图片预加载的方法;该方法利用DOM,不仅仅预加载图片,还会预加载CSS/JavaScript等相关的东西;使用Ajax比直接使用JavaScript优越之处在于JavaScript和CSS的加载不会影响到当前页面;该方法简洁/高效

window.onload = function() {  
    setTimeout(function() {  
        // XHR to request a JS and a CSS  
        var xhr = new XMLHttpRequest();  
        xhr.open('GET', 'http://domain.tld/preload.js');  
        xhr.send('');  
        xhr = new XMLHttpRequest();  
        xhr.open('GET', 'http://domain.tld/preload.css');  
        xhr.send('');  
        // preload image  
        new Image().src = "http://domain.tld/preload.png";  
    }, 1000);  
};

上面代码预加载了preload.js/preload.css/preload.png,1000毫秒的超时是为了防止脚本挂起,而导致正常页面出现功能问题;下面我们看看如何用JavaScript来实现该加载过程:

window.onload = function() {   
    setTimeout(function() {   
        // reference to <head>  
        var head = document.getElementsByTagName('head')[0];   
        // a new CSS  
        var css = document.createElement('link');  
        css.type = "text/css";  
        css.rel  = "stylesheet";  
        css.href = "http://domain.tld/preload.css";   
        // a new JS  
        var js  = document.createElement("script");  
        js.type = "text/javascript";  
        js.src  = "http://domain.tld/preload.js";    
        // preload JS and CSS  
        head.appendChild(css);  
        head.appendChild(js);    
        // preload image  
        new Image().src = "http://domain.tld/preload.png";    
    }, 1000);    
};

这里,我们通过DOM创建三个元素来实现三个文件的预加载;正如上面提到的那样,使用Ajax加载文件不会应用到加载页面上;从这点上看,Ajax方法优越于JavaScript

补充知识
屏幕可视窗口大小

<script>
  //原生方法
  window.innerHeight || //标准浏览器及IE9+
  document.documentElement.clientHeight || //标准浏览器及低版本IE标准模式
  document.body.clientHeight  //低版本混杂模式
  //jQuery方法 
  $(window).height();
</script>
滚动条滚动的距离
<script>
  //原生方法
  window.pagYoffset || //标准浏览器及IE9+
  document.documentElement.scrollTop || //兼容ie低版本的标准模式
  document.body.scrollTop //兼容混杂模式;
  //jQuery方法 
  $(document).scrollTop();
</script>
获取元素的尺寸
<script>
  $(o).width() = o.style.width;
  $(o).innerWidth() = o.style.width+o.style.padding;
  $(o).outerWidth() = o.offsetWidth = o.style.width+o.style.padding+o.style.border;
  $(o).outerWidth(true) = o.style.width+o.style.padding+o.style.border+o.style.margin;
</script>
注意:

要使用原生的style.xxx方法获取属性,这个元素必须已经有内嵌的样式,如<div style="...."></div>;

如果原先是通过外部或内部样式表定义css样式,必须使用o.currentStyle[xxx] || document.defaultView.getComputedStyle(0)[xxx]来获取样式值

获取元素的位置信息
<script>
  //原生方法
  getoffsetTop();
  //jQuery方法 
  $(o).offset().top //元素距离文档顶的距离
  $(o).offset().left //元素距离文档左边缘的距离
  // 顺便提一下返回元素相对于第一个以定位的父元素的偏移距离,注意与上面偏移距的区别;
  jQuery:position() //返回一个对象
  $(o).position().left = o.style.left;
  $(o).position().top = o.style.top;
</script>

函数节流和函数防抖

  1. 什么是css精灵图(sprite)?

css精灵图(sprite)直译为“CSS精灵”,也被称为通常被解释为“CSS图像拼合”、“CSS贴图定位”或“CSS图片精灵”、“CSS雪碧图”,是一种网页图片应用处理方式。其实就是把一个页面涉及到的所有零星图片都包含到一张大图中去,这样一来,当访问该页面时,载入的图片就不会像以前那样一幅一幅地慢慢显示出来了。

2.使用css精灵图(sprite)的方法

css精灵图(sprite)其实就是通过将多个图片融合到一张图里面,然后通过CSS background背景定位技术技巧布局网页背景。在需要用到图片的时候,现阶段是通过CSS属性background-image组合background-repeat, background-position等来实现图片的显示。

3.代码实现:
使用到的精灵图(sprite)

https://www.cnblogs.com/walls/p/6399837.html
https://www.jianshu.com/p/c8b86b09daf0
概念 函数防抖(debounce)
函数防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次。
比如生活中的坐公交,就是一定时间内,如果有人陆续刷卡上车,司机就不会开车。只有别人没刷卡了,司机才开车。
简单的说,当一个动作连续触发,则只执行最后一次。

打个比方,坐公交,司机需要等最后一个人进入才能关门。每次进入一个人,司机就会多等待几秒再关门。

函数防抖的应用场景,最常见的就是用户注册时候的手机号码验证和邮箱验证了。只有等用户输入完毕后,前端才需要检查格式是否正确,如果不正确,再弹出提示语。以下还是以页面元素滚动监听的例子,来进行解析:

// 函数防抖
var timer = false;
document.getElementById("debounce").onscroll = function(){
    clearTimeout(timer); // 清除未执行的代码,重置回初始化状态

    timer = setTimeout(function(){
        console.log("函数防抖");
    }, 300);
};  

函数防抖的要点,也是需要一个setTimeout来辅助实现。延迟执行需要跑的代码。
 如果方法多次触发,则把上次记录的延迟执行代码用clearTimeout清掉,重新开始。
 如果计时完毕,没有方法进来访问触发,则执行代码。

这个方法的作用是监听ID为debounce元素的滚动事件
 进入滚动事件方法体的时候,做的第一件事就是清除上次未执行的setTimeout。而setTimeout的引用id由变量timer记录。
 clearTimeout方法,允许传入无效的值。所以这里直接执行clearTimeout即可。
 然后,将需要执行的代码放入setTimeout中,再返回setTimeout引用给timer缓存。
 如果倒计时300ms以后,还没有新的方法触发滚动事件,则执行setTimeout中的代码。

函数防抖的实现重点,就是巧用setTimeout做缓存池,而且可以轻易地清除待执行的代码。
 其实,用队列的方式也可以做到这种效果。这里就不深入了。

函数节流(throttle)
限制一个函数在一定时间内只能执行一次。
函数节流是指一定时间内js方法只跑一次。

比如人的眨眼睛,就是一定时间内眨一次。这是函数节流最形象的解释

举个例子,乘坐地铁,过闸机时,每个人进入后3秒后门关闭,等待下一个人进入。

函数节流应用的实际场景,多数在监听页面元素滚动事件的时候会用到。因为滚动事件,是一个高频触发的事件。以下是监听页面元素滚动的示例代码:

// 函数节流
var canRun = true;
document.getElementById("throttle").onscroll = function(){
    if(!canRun){
        // 判断是否已空闲,如果在执行中,则直接return
        return;
    }

    canRun = false;
    setTimeout(function(){
        console.log("函数节流");
        canRun = true;
    }, 300);
};

函数节流的要点是,声明一个变量当标志位,记录当前代码是否在执行。
 如果空闲,则可以正常触发方法执行。
 如果代码正在执行,则取消这次方法执行,直接return

 这个方法的作用是监听ID为throttle元素的滚动事件。
 当canRun为true,则代表现在的滚动处理事件是空闲的,可以使用。
 通过关卡if(!canRun),等于就拿到了通行证。
 然后下一步的操作就是立马将关卡关上canRun=false。
 这样,其他请求执行滚动事件的方法,就被挡回去了。
 接着用setTimeout规定最小的时间间隔300,接着再执行setTimeout方法体里面的内容。
 最后,等setTimeout里面的方法都执行完毕,才释放关卡canRun=true,
 允许下一个访问者进来。

这个函数节流的实现形式,需要注意的是执行的间隔时间是>=300ms。如果具体执行的方法是包含callback的,也可以将canRun=true这一步放到callback中。理解了函数节流的关卡设置重点,其实改起来就简单多了

路由懒加载

css雪碧图

雪碧图合成工具,grunt等自动化工具可以自动生成雪碧图
https://www.cnblogs.com/joyho/articles/3715260.html

1.什么是css精灵图(sprite)?

css精灵图(sprite)直译为“CSS精灵”,也被称为通常被解释为“CSS图像拼合”、“CSS贴图定位”或“CSS图片精灵”、
“CSS雪碧图”,是一种网页图片应用处理方式。
其实就是把一个页面涉及到的所有零星图片都包含到一张大图中去,这样一来,当访问该页面时,载入的图片就不会像以前那样一幅一幅地慢慢显示出来了。

2.使用css精灵图(sprite)的方法

css精灵图(sprite)其实就是通过将多个图片融合到一张图里面,
然后通过CSS background背景定位技术技巧布局网页背景。
在需要用到图片的时候,现阶段是通过CSS属性background-image组合background-repeat, background-position等来实现图片的显示。

3.代码实现:
使用到的精灵图(sprite)
https://blog.csdn.net/pupilxiaoming/article/details/79852149
https://blog.csdn.net/zjsfdx/article/details/87932322
https://www.cnblogs.com/dawdler/p/9344672.html

CSS Sprites:国内俗称 CSS 精灵,这是将多张图片合并成一张图片达到减少 HTTP 请求的一种解决方案,可以通过 CSS background 属性来访问图片内容。这种方案同时还可以减少图片总字节数。
合并 CSS 和 JS 文件:现在前端有很多工程化打包工具,如:grunt、gulp、webpack等。为了减少 HTTP 请求数量,可以通过这些工具再发布前将多个 CSS 或者 多个 JS 合并成一个文件。
采用 lazyLoad:俗称懒加载,可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容。这样就控制了网页资源一次性请求数量。

控制资源文件加载优先级
浏览器在加载 HTML 内容时,是将 HTML 内容从上至下依次解析,解析到 link 或者 script 标签就会加载 href 或者 src 对应链接内容,为了***时间展示页面给用户,就需要将 CSS 提前加载,不要受 JS 加载影响。

一般情况下都是 CSS 在头部,JS 在底部。

利用浏览器缓存
浏览器缓存是将网络资源存储在本地,等待下次请求该资源时,如果资源已经存在就不需要到服务器重新请求该资源,直接在本地读取该资源。

减少重排(Reflow)
基本原理:重排是 DOM 的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证 DOM 树上的所有其它结点的 visibility 属性,这也是 Reflow 低效的原因。如果 Reflow 的过于频繁,CPU 使用率就会急剧上升。

减少 Reflow,如果需要在 DOM 操作时添加样式,尽量使用 增加 class 属性,而不是通过 style 操作样式。

减少 DOM 操作

https://blog.csdn.net/qq_43677445/article/details/90375605

图标使用 IconFont 替换
前端性能优化
https://www.jianshu.com/p/be5aea4a222f

发布了45 篇原创文章 · 获赞 4 · 访问量 1051

猜你喜欢

转载自blog.csdn.net/weixin_44990056/article/details/104293046