关于延迟加载JavaScript,延迟加载JavaScript

1:实际需求
  大型网站往往很矛盾,想用户在首页看到更多东西,又不想浪费太多服务器流量。比如一个有3屏的首页。可能50%的用户进首页的目的是点击首页的连接,到子页面。
那么我们的网站却为100%的用户加载了 3个
屏幕的所有内容。如果可以按需加载内容。就可以节约更多资源,做更多好的应用。

  • defer为true:延迟加载脚本,在文档完成解析完成开始执行,并且在DOMContentLoaded事件之前执行完成。
  • 威尼斯真人娱乐平台 ,async(HTML5新增的属性)为true:异步加载脚本,下载完毕后再执行,在window的load事件之前执行完成

异步加载:

1:在script元素中加上async属性(为了兼容老版本的IE 加上defer)

2:动态的添加script标签

eg:(function(){

if(window.attachEvent){

window.attachEvent(“load”, asyncLoad);

}else{

window.addEventListener(“load”, asyncLoad);

}

威尼斯人网上赌场 ,var asyncLoad = function(){

var ga = document.createElement(‘script’);

ga.type = ‘text/javascript’;

ga.async = true;

ga.src = (‘https:’ == document.location.protocol ? ” :
”) + ‘.google-analytics.com/ga.js’;

var s = document.getElementsByTagName(‘script’)[0];

s.parentNode.insertBefore(ga, s);

}

)();

3:通过eval()执行js代码

关于延迟加载JavaScript,延迟加载JavaScript

JavaScript的延迟加载是那些在web上,能让你想抓狂地去寻找解决方案的问题之一。

很多人说“那就用defer”或“async”,甚至有些人说“那就将你的javascript代码放在页面代码底部”。

上述方法都不能解决在web页面完全加载后,再加载外部js的问题。上述方法也会偶尔让你收到Google页面速度测试工具的“延迟加载javascript”警告。所以这里的解决方案将是来自Google帮助页面的推荐方案。

如何延迟加载JavaScript

下面是Google推荐的代码。这些代码应被放置在</body>标签前(接近HTML文件底部)。另外,我将外部JS文件名突出显示。

<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "defer.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
</script>

这里做了什么?
这段代码意思是等到整个文档加载完后,再加载外部文件“defer.js”。

具体说明

1.复制上面代码

2.粘贴代码到HTML的</body>标签前 (靠近HTML文件底部)

3.修改“defer.js”为你的外部JS文件名

4.确保你文件路径是正确的。例如:如果你仅输入“defer.js”,那么“defer.js”文件一定与HTML文件在同一文件夹下。

这段代码能用在哪里(和哪里不能用)

这段代码直到文档加载完才会加载指定的外部JS文件。因此,不应该把那些页面正常加载需要依赖的javascript代码放在这里。而应该将JavaScript代码分成两组。一组是因页面需要而立即加载的javascript代码,另外一组是在页面加载后进行操作的javascript代码(例如添加click事件或其他东西)。这些需等到页面加载后再执行的JavaScript代码,应放在一个外部文件,然后再引进来。

例如,在这页面我使用上述文件进行延迟加载 – Google analytics,Viglink
(我怎么赚钱),和显示在底部的Google+徽章(我的社交媒体)。这对于我来说,没有理由在初始页面加载时加载这些文件,因为初始阶段都没必要加载上述无关紧要的内容。也许在你的页面中也有同样性质的文件。那你难道想让用户在看到网页内容之前,还要等待这些文件加载吗?

为什么不使用其它方法呢?

直接插入代码、将脚本放置在底部和使用“defer”或“async”,这几种方法都不能达到先加载页面后加载JS的目的,而且它们肯定不能在各个浏览器上表现一致。

它为什么重要?

它的重要性是由于Google将页面速度作为排名因素之一而且用户也希望能快速加载页面。另外对于移动搜索引擎优化也是非常重要的。Google根据页面最初加载时间来衡量页面速度。这意味着你必须尽可能快地得到页面的load事件。页面最初加载时间是Google用来评价你的web页面质量(而且别忘记用户在等待页面的加载)。Google积极推进和推荐将上述的无关紧要的内容按重要性排列,让所有资源(js,css,images等)脱离关键的渲染路径,而且这样做是值得去努力的。如果这样能取悦用户,且让Google开心,你很应该这样做。

用法示例

我已创建一个页面,在这个页面你可看到这段代码的使用。

让你测试的示例文件

好的,为了说明,我已制作几个示例页面让你进行测试。每个页面都做同一样的事情。这是一个普通的HTML页面,含有一个等待2秒然后输出“hello
world”的javascript脚本。你可以测试这些文件,然后你会看到只有一种方法,它的加载时间是不包括2秒的等待时间。

直接插入脚本的页面 – 点击这里

带有使用“defer”外部脚本的页面 – 点击这里
使用上述推荐代码的页面 – 点击这里

关键点

压倒一切的首要任务应该是尽可能快地交付内容给用户。而我们一直没想着如何对待我们的javascript代码。但用户不应该为一些无关紧要的脚本,而被迫地为内容而作出等待。无论你的页脚多酷,都没理由让一个可能从不滚动到页脚的用户,去加载那些让页脚变酷的javascript文件。

以上所述就是本文的全部内容了,希望大家能够喜欢。

JavaScript的延迟加载是那些在web上,能让你想抓狂地去寻找解决方案的问题之一。
很多人说“那就…

2:解决方案
  用客户端语言来判断用户当前的可视范围,只加载用户可视范围的内容。最主要的是图片。因为文字信息,相对较小,其他多媒体内容相对占用服务器流量更多。
3:演示例子(最后提供)
4:解析
  首先我们要分析下,这个效果会有一个
最外面的容器。他包涵了里面需要延迟加载一些内容。容器一般可能是浏览器窗口本身(window),或者一个有滚动条的DIV。
OK,我们必须获取这个容器的一些参数。比如
可视宽度,可视高度,水平卷去宽度,垂直卷去高度。我使用下面的程序。
  4.1:获取容器对象属性

延迟加载:

1:settimeOut()

2:将js放在底部

复制代码 代码如下:

_this.docInfo=function(){//获取容器的相关信息
var d={},db= (wf)? document.body : warpper,
dd=(wf) ? document.documentElement : warpper;
if(sys.ie){
d.offh=dd.offsetHeight;//可视区域H
d.offw=dd.offsetWidth;//可视区域W
}else{
if(wf){
d.offw=window.innerWidth;//可视区域H
d.offh=window.innerHeight;//可视区域W
}else{
d.offh=dd.offsetHeight;//可视区域H
d.offw=dd.offsetWidth;//可视区域W
}
}
d.jtop=(wf) ? db.scrollTop+dd.scrollTop : db.scrollTop ;//垂直卷去高度
d.jleft=(wf) ? db.scrollLeft+dd.scrollLeft :
db.scrollLeft;//水平卷去宽度
//被卷去的宽度 window 使用两个相加 div的卷曲就直接使用scrollLeft就OK
$j(“bbb”).innerHTML=d.offh+’,’+d.offw+’,’+d.jtop+’,’+d.jleft
return d;
}
//注意在非IE 浏览器下 获取非window对象的可视区域 使用offsetHeight 和
offsetWidth (跟IE 一样)
//在非IE 下获取 window对象的可视区域 则要使用 window.innerWidth
和window.innerHeight
//也就是说在非IE 下的 window 和 非window 对象的
可视区域获取是不一样的。

  4.2:获取加载内容的信息
    我们主要获取加载对象距离 页面容器对象的距离 。
IE 6 7会有个BUG

复制代码 代码如下:

wtop=sys.ie ? (sys.ie[1]==’6.0′ || sys.ie[1]==’7.0′) ? 0 :
warpper.offsetTop : warpper.offsetTop,
wleft=sys.ie ? (sys.ie[1]==’6.0′ || sys.ie[1]==’7.0′) ? 0 :
warpper.offsetLeft : warpper.offsetLeft,

复制代码 代码如下:

getoff=function(o){//获取IMG对象的 offw and offh
o.innerHTML=(o.offsetTop-wtop) +’,’+ (o.offsetLeft-wleft);
return (o.offsetTop-wtop) +’,’+ (o.offsetLeft-wleft);
//注意 o.offsetTop 在chrome下要等window.onload以后才能正确获取
};

  4.3:加载主程序
    他主要负责加载当前在可视范围内对象。那么我们必须去遍历所有要加载的对象。判断对象是否在当前的加载中。
然后加载他。我下面会有一个图。(方法可能不太好)

复制代码 代码如下:

_this.Load=function(){
var hereline=[];
hereline[1]=doc.offh+doc.jtop;
hereline[2]=doc.offw+doc.jleft;
for(i=0;i<imgs.length;i++){
if(imgs[i][1] != undefined){//判断当前对象是否已经加载过
var jj=hereline[1] – imgs[i][1] < doc.offh +130 &&
hereline[1] – imgs[i][1] > 0 ? true : false,
jjj=hereline[2] – imgs[i][2] < doc.offw +270 && hereline[2] –
imgs[i][2] > 0 ? true : false;
if(jj && jjj){
imgall[i].innerHTML+=’第’+(++j)+’个加载’;
imgs[i][1]=undefined;
}
}
}
if( j >= imgs.length){//判断是否已经全部加载完毕
//取消时间绑定
alert(“已经全部加载完成,程序将不再执行”)
warpper.onscroll=null;
warpper.onresize=null;
}
}

我不太喜欢我的判断程序,但是暂时没找到,或者我没理解更好的算法。所以就先用这个了。
大体的意思:用容器的可视高度+容器滚动高度 – 对象距离距离容器距离 >
容器可视 + 对象本身高或宽 就证明在加载范围。(绕口令)
我们还必须把
已经加载过的对象排除在外。因为加载过的对象也满足以上公式,同时也可以少判断一些。
imgs[i][1]=undefined;
if(imgs[i][1] != undefined){//判断当前对象是否已经加载过
  特别注意(看图)
威尼斯人网上赌场 1
看上图 A B C D。 分别有4个不同的角露在了
可视范围内。所以这4个对象是需要加载的。

如果只考虑对象的某个点,或者某个线来判断对象是否在可视范围,可能带来不好的体验。

由于有上面这种情况,也给我们的编程(判断是否在可视范围内)增加了难度。

我上面的方法,是可以完成了。(如果有发现BUG
,请给我指点。其实我也有点晕了。)

最后还有几个技巧,比如

  1:对象全部加载完了。就应该去掉容器对象事件触发。

  2:尽量优化判断对象是否在可视范围,或者遍历的对象的算法。可以节约很多浏览器资源。

  3:cloudgamer 还提到一个
延迟触发,就是快速的滑动滚动条,延迟一下也是一个小的优化。

5:推荐文章

  cloudgamer 的
他讲的很详细,也比我做的要好。所以推荐去学习他的这个效果哦。很多东西我也借鉴他的。

还有就是感谢他的指点。 Lazyload 延迟加载效果
6:我的源码

复制代码 代码如下:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“;
<html xmlns=”;
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″
/>
<title>lazyload</title>
</head>
<body>
<style type=”text/css”>
body{ margin:0px; padding:0; font-size:12px;}
.jelle_box{width:270px; height:129px; border:1px solid #CCC;
float:left;}
</style>
<input type=”button” value=”重新开始” onclick=”lazyload().judge();”
/>
<div style=”width:100%; height:500px; overflow:scroll; border:2px
solid #999;” id=”jelle_abcd”>
<div id=”aaa” style=”width:2500px; height:800px; margin:10px;”>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
<div class=”jelle_box”></div>
</div>
</div>
<div style=” height:30px” id=”bbb”></div>
<script type=”text/javascript”>
(function(){
window.lazyload=function(){
var _this={},//方法集合
imgsurl=[‘baidu_logo_2.gif’]//最开始是用来加载图片的。这里是需要加载图片的地址集合
imgs=[],//全部IMG 数据 格式为
[[url,offw,offh],[url,offw,offh]]
i=0,//循环变量
j=0,//判断当前的加载个数
warpper=document.getElementById(‘jelle_abcd’),//window,//容器对象
wf=(warpper==window) ? true : false;
doc={offw:0,offh:0,jtop:0,jleft:0},//包含一些 容器对象当前的一些属性
sys=(function(){//不必紧张这只是一个判断浏览器的函数,你可以使用很多方法来判断浏览器
var ua=navigator.userAgent.toLowerCase(),sys={};
sys.firefox=ua.match(/firefox\/([\d\.]+)/);
sys.ie=ua.match(/msie\s([\d\.]+)/);
sys.chrome=ua.match(/chrome\/([\d\.]+)/);
return sys;
})(),
$j=function(id){return document.getElementById(id);},
imgall=$j(‘aaa’).getElementsByTagName(‘DIV’),
getoff=function(o){//获取IMG对象的 offw and offh
//alert(o.width)
o.innerHTML=(o.offsetTop-warpper.offsetTop) +’,’+
(o.offsetLeft-warpper.offsetLeft);
return (o.offsetTop-warpper.offsetTop) +’,’+
(o.offsetLeft-warpper.offsetLeft);
//注意 o.offsetTop 在chrome下要等window.onload以后才能正确获取
};
//o.offsetTop获取对象距离浏览器顶部的距离
必须减去外面容器的距离浏览器的距离。(如果使用window容器就不用了)
(function(){//初始化容器对象绑定事件==
if(wf){
window.onscroll=function(){_this.judge();};
window.onresize=function(){_this.judge();};
}else{
warpper.onscroll=function(){_this.judge();}
warpper.onresize=function(){_this.judge();}
}
window.onload=function(){setTimeout(_this.judge,500);};
})()
//容器对象设置结束
for( i ; i<imgall.length ; i++ ){//初始化imgs 数组
var arr=[],off;
off=getoff(imgall[i]);
//alert(off)
arr.push(imgsurl[0]);
arr.push((off.split(‘,’)[0]));
arr.push((off.split(‘,’)[1]));
imgs.push(arr);
}
_this.Load=function(){
var hereline=[];
hereline[1]=doc.offh+doc.jtop;
hereline[2]=doc.offw+doc.jleft;
for(i=0;i<imgs.length;i++){
if(imgs[i][1] != undefined){//判断当前对象是否已经加载过
var jj=hereline[1] – imgs[i][1] < doc.offh +130 &&
hereline[1] – imgs[i][1] > 0 ? true : false,
jjj=hereline[2] – imgs[i][2] < doc.offw +270 && hereline[2] –
imgs[i][2] > 0 ? true : false;
if(jj && jjj){
imgall[i].innerHTML+=’第’+(++j)+’个加载’;
imgs[i][1]=undefined;
}
}
}
if( j >= imgs.length){//判断是否已经全部加载完毕
//取消时间绑定
alert(“已经全部加载完成,程序将不再执行”)
warpper.onscroll=null;
warpper.onresize=null;
}
}
_this.docInfo=function(){//获取容器的相关信息
var d={},db= (wf)? document.body : warpper,
dd=(wf) ? document.documentElement : warpper;
if(sys.ie){
d.offh=dd.offsetHeight;//可视区域H
d.offw=dd.offsetWidth;//可视区域W
}else{
if(wf){
d.offw=window.innerWidth;//可视区域H
d.offh=window.innerHeight;//可视区域W
}else{
d.offh=dd.offsetHeight;//可视区域H
d.offw=dd.offsetWidth;//可视区域W
}
}
d.jtop=(wf) ? db.scrollTop+dd.scrollTop : db.scrollTop ;//垂直卷去高度
d.jleft=(wf) ? db.scrollLeft+dd.scrollLeft :
db.scrollLeft;//水平卷去宽度
//被卷去的宽度 window 使用两个相加 div的卷曲就直接使用scrollLeft就OK
$j(“bbb”).innerHTML=d.offh+’,’+d.offw+’,’+d.jtop+’,’+d.jleft
return d;
}
//注意在非IE 浏览器下 获取非window对象的可视区域 使用offsetHeight 和
offsetWidth (跟IE 一样)
//在非IE 下获取 window对象的可视区域 则要使用 window.innerWidth
和window.innerHeight
//也就是说在非IE 下的 window 和 非window 对象的
可视区域获取是不一样的。
_this.judge=function(){//后来发现不用判断方向了
var d=_this.docInfo();
if( d.jtop != doc.jtop || d.jleft != doc.jleft || d.offw > doc.offw
|| d.offh > doc.offh){
//判断是否需要执行加载
//条件为 被卷去的 y x 变化 或者 窗口大小 发生变化触发
doc.jtop = d.jtop;
doc.offh = d.offh;
doc.jleft = d.jleft;
doc.offw = d.offw;
_this.Load();//加载程序
}
}
//setTimeout(_this.judge,500);//执行初始化加载
//setTimeout 防止onload 和 onscroll的重复执行
//也就是本来就有onscroll的时候 最先执行了onload
return _this;
}
})()
lazyload();
</script>
</body>
</html>

大型网站往往很矛盾,想用户在首页看到更多东西,又不想浪费太多服务器流量。比如一个有3屏的首页。可能50%的用户进首页…

发表评论

电子邮件地址不会被公开。 必填项已用*标注