预加载与懒加载,我们经常经常用到,这些技术不仅仅限于图片加载,我们今天讨论的是图片加载:
一、什么是图片预加载与懒加载:
图片预加载: 顾名思义,图片预加载就是在网页全部加载之前, 提前加载图片。 当用户需要查看时可直接从本地缓存中渲染, 以提供给用户更好的体验,减少等待的时间。否则,如果一个页面的内容过于庞大,没有使用预加载技术的页面就会长时间的展现为一片空白,这样浏览者可能以为图片预览慢而没兴趣浏览,把网页关掉,这时,就需要图片预加载。 当然这种做法实际上牺牲了服务器的性能换取了更好的用户体验。
图片懒加载(缓载 ): 延迟加载图片或符合某些条件时才加载某些图片。这样做的好处是减少不必要的访问数据库或延迟访问数据库的次数,因为每次访问数据库都是比较耗时的即只有真正使用该对象的数据时才会创建。 懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数。
二、 图片预加载与懒加载的区别:
两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预载则会增加服务器前端压力。
三、 图片预加载与懒加载 实现:
1、实现 图片预加载:
实现预载的方法非常多,可以用CSS(background)、JS(Image)、HTML(<img />)都可以。常用的是new Image();,设置其src来实现预载,再使用onload方法回调预载完成事件。只要浏览器把图片下载到本地,同样的src就会使用缓存,这是最基本也是最实用的预载方法。当Image下载完图片头后,会得到宽和高,因此可以在预载前得到图片的大小(我所知的方法是用记时器轮循宽高变化)。一般实现预载的工具类,都实现一个Array来存需要预载的URL,然后实现Finish、Error、SizeChange等常用事件,可以由用户选择是顺序预载或假并发预载。Jquery的PreLoad可以用于预载。
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>img ready</title>
</head>
<body>
<div>
<p>
<button id="testReadyBtn">开始加载图片</button>
<button id="clsCacheBtn">清空缓存</button>
<p>(如果图片加载过后,浏览器会缓存)</p>
</p>
<div id="status" style="display:none">
<p><strong>imgReady:</strong>
<p>
<p id="statusReady"></p>
<p><strong>imgLoad:</strong></p>
<p id="statusLoad">
<p>
</div>
<div id="imgWrap"></div>
<div style="display:none"></div>
</div>
</body>
<script>
var imgReady = function(url, callback, error) {
var width, height, intervalId, check, div, img = new Image(),
body = document.body;
img.src = url;
// 从缓存中读取
if (img.complete) {
return callback(img.width, img.height);
};
// 通过占位提前获取图片头部数据
if (body) {
div = document.createElement('div');
div.style.cssText = 'visibility:hidden;position:absolute;left:0;top:0;width:1px;height:1px;overflow:hidden';
div.appendChild(img)
body.appendChild(div);
width = img.offsetWidth;
height = img.offsetHeight;
check = function() {
if (img.offsetWidth !== width || img.offsetHeight !== height) {
clearInterval(intervalId);
callback(img.offsetWidth, img.clientHeight);
img.onload = null;
div.innerHTML = '';
div.parentNode.removeChild(div);
};
};
intervalId = setInterval(check, 150);
};
// 加载完毕后方式获取
img.onload = function() {
callback(img.width, img.height);
img.onload = img.onerror = null;
clearInterval(intervalId);
body && img.parentNode.removeChild(img);
};
// 图片加载错误
img.onerror = function() {
error && error();
clearInterval(intervalId);
body && img.parentNode.removeChild(img);
};
};
</script>
<script>
/* demo script */
window.onload = function() {
var imgUrl = 'https://p1.ssl.qhimg.com/dr/705_705_/t019473cbfb1ccd6dbb.png?size=705x705',
testReadyBtn = document.getElementById('testReadyBtn'),
clsCacheBtn = document.getElementById('clsCacheBtn'),
status = document.getElementById('status'),
statusReady = document.getElementById('statusReady'),
statusLoad = document.getElementById('statusLoad'),
imgWrap = document.getElementById('imgWrap');
var imgLoad = function(url, callback) {
var img = new Image();
img.src = url;
if (img.complete) {
callback(img.width, img.height);
} else {
img.onload = function() {
callback(img.width, img.height);
img.onload = null;
};
};
};
testReadyBtn.onclick = function() {
var that = this;
that.disabled = true;
status.style.display = 'block';
statusLoad.innerHTML = statusReady.innerHTML = 'Loading...';
imgWrap.innerHTML = '<img src="' + imgUrl + '" />';
// 使用占位方式快速获取大小
imgReady(imgUrl, function(width, height) {
statusReady.innerHTML = 'width:' + width + '; height:' + height;
}, function() {
statusReady.innerHTML = 'Img Error!';
});
// 使用传统方式获取大小
imgLoad(imgUrl, function(width, height) {
statusLoad.innerHTML = 'width:' + width + '; height:' + height;
that.disabled = false;
}, function() {
statusLoad.innerHTML = 'Img Error!';
that.disabled = false;
});
};
clsCacheBtn.onclick = function() {
imgUrl += new Date().getTime();
status.style.display = 'none';
imgWrap.innerHTML = '';
};
};
</script>
</html>
2、 懒加载 实现:
第一种是纯粹的延迟加载,使用setTimeOut或setInterval进行加载延迟,如果用户在加载前就离开了页面,那么就不会加载。
第二种是条件加载,符合某些条件,或触发了某些事件才开始异步下载。
第三种是可视区加载,即仅加载用户可以看到的区域,这个主要由监控滚动条来实现,一般会在距用户看到某图片前一定距离遍开始加载,这样能保证用户拉下时正好能看到图片。
Jquery的Lazy Load用于图片缓载
<html>
<head>
<meta charset="utf-8" />
<title>原生Js图片延迟加载</title>
<style type="text/css">
* {
margin: 0;
padding: 0
}
img.scrollLoading {
border: 1px solid #ccc;
display: block;
margin-top: 10px;
}
</style>
</head>
<body>
<div id="content">
</div>
</body>
</html>
<script type="text/javascript">
var _CalF = {
zsl: function(object) { //选择器
if (object === undefined) return;
var getArr = function(name, tagName, attr) {
var tagName = tagName || '*',
eles = document.getElementsByTagName(tagName),
clas = (typeof document.body.style.maxHeight === "undefined") ? "className" : "class"; //ie6
attr = attr || clas,
Arr = [];
for (var i = 0; i < eles.length; i++) {
if (eles[i].getAttribute(attr) == name) {
Arr.push(eles[i]);
}
}
return Arr;
};
if (object.indexOf('#') === 0) { //#id
return document.getElementById(object.substring(1));
} else if (object.indexOf('.') === 0) { //.class
return getArr(object.substring(1));
} else if (object.match(/=/g)) { //attr=name
return getArr(object.substring(object.search(/=/g) + 1), null, object.substring(0, object.search(/=/g)));
} else if (object.match(/./g)) { //tagName.className
return getArr(object.split('.')[1], object.split('.')[0]);
}
},
getPosition: function(obj) { //获取元素在页面里的位置和宽高
var top = 0,
left = 0,
width = obj.offsetWidth,
height = obj.offsetHeight;
while (obj.offsetParent) {
top += obj.offsetTop;
left += obj.offsetLeft;
obj = obj.offsetParent;
}
return {
"top": top,
"left": left,
"width": width,
"height": height
};
}
};
//添加图片list
var _temp = [];
for (var i = 1; i < 21; i++) {
_temp.push(
'<img class="scrollLoading" data-src="https://p1.ssl.qhimg.com/dr/705_705_/t019473cbfb1ccd6dbb.png?size=705x705' +
i +
'.jpg" src="http://images.cnitblog.com/blog/150659/201306/23160223-c81dd9aa9a2a4071a47b0ced2c9118bc.gif" /><br />图片' +
i);
}
_CalF.zsl("#content").innerHTML = _temp.join("");
function scrollLoad() {
this.init.apply(this, arguments);
}
scrollLoad.prototype = {
init: function(className) {
var className = "img." + className,
imgs = _CalF.zsl(className),
that = this;
this.imgs = imgs;
that.loadImg();
window.onscroll = function() {
that.time = setTimeout(function() {
that.loadImg();
},
400);
}
},
loadImg: function() {
var imgs = this.imgs.reverse(),
//获取数组翻转
len = imgs.length;
if (imgs.length === 0) {
clearTimeout(this.time);
return;
}
for (var j = len - 1; j >= 0; j--) { //递减
var img = imgs[j],
imgTop = _CalF.getPosition(img).top,
imgSrc = img.getAttribute("data-src"),
offsetPage = window.pageYOffset ? window.pageYOffset : window.document.documentElement.scrollTop,
//滚动条的top值
bodyHeight = document.documentElement.clientHeight; //body的高度
if ((offsetPage + bodyHeight / 2) > (imgTop - bodyHeight / 2)) {
img.src = imgSrc;
this.imgs.splice(j, 1);
}
}
}
}
var img1 = new scrollLoad("scrollLoading");
</script>
<!-- 获取屏幕的分辨率 -->
<script type="text/javascript">
document.write('您的显示器分辨率为:\n' + screen.width + '*' + screen.height + '</br>');
var ww = document.getElementById("con").offsetWidth,
w = screen.width / ww,
h = screen.height / ww,
r = Math.round(Math.sqrt(w * w + h * h) / 2.54);
document.write('您的显示器尺寸为:\n' + (screen.width / ww).toFixed(1) + '*' + (screen.height / ww).toFixed(1) + ' cm, ' + r +
'寸<br/>');
</script>