无限滚动的优化方案(二):懒加载实现

之前对预加载的实现方案做了介绍,这一篇文章主要是我对图片的懒加载的实现的一个总结。主要包括:

  1. 视区检测
  2. 图片懒加载及延迟显示

实例简介

之前一直对单页应用有兴趣,所以自己写了一个前端路由,相关的文章见这里,这个单页应用采取hash的方式实现路由。最终的实例页面见这里。仓库在这里是一个经典的单页应用。要做优化的就是主页的信息滚动。这些信息通过ajax从服务器端获取,这里为了方便,服务器端会一直返回数据,哪怕是重复的。页面如下:

Paste_Image.png

懒加载

可以看到,页面中,每一条消息都有一个图片,这个时候,如果在dom刚刚建立好,就对所有的图片进行加载,此时,占用过多的下载通道(我的是每次显示10条消息,接近页面底部时会预加载),会导致后面的信息加载速度变慢,用户体验不好。而图片懒加载是指:图片进入用户视野才会进行加载,而不是在dom树一构建好就进行加载。 道理很简单,但是我在实现的过程中还是碰到了一些问题,下面就是我的实现方案。

懒加载实现方案

总体变量以及函数定义

//记录图片的序号
let num = 0;
//记录是否正在获取数据,保证请求只做一次
let state = true;
//记录图片数据,index,src,height三个关键元素
var img_data =[];
//记录表单的距离页面顶端的距离
var list_height = 0;

function getH(obj) {
   //获得对象距离页面顶端的距离
}
function lazy_load(){
  //图片懒加载的实现函数
}
function getInfo(){
   //从服务器端获取商家发布的新信息
   //并向图片数据中存放图片信息 
}
function main(){
  //主函数
  //实现初始化
  //滚动事件的绑定等
}

获取元素相对页面顶部的高度

这个函数其实不难,主要涉及到目标元素下面几个属性:

  1. node.offsetTop:相对其父元素的位置
  2. node.offsetParent: 元素的父元素
    所以,要获取元素相对页面顶部的高度,其实只需要进行递归或者迭代就能实现,这里采用迭代实现:
function getH(obj) {
    var h = 0;
    while (obj) {
        h += obj.offsetTop;
        obj = obj.offsetParent;
    }
    return h;
}

数据的缓存

程序中,通过Ajax从服务器获取数据,每次最多获取10条,在dom中,img标签最开始并不指定src,src存储在ajax获取到的信息中,我将其存入:img_data中,与它一同存入的,还有该图片的高度height,第几条信息index。
这里的height,可以采用上面的迭代得到,但是每次迭代对资源损耗比较大,事实上也是没有必要的,因为每条信息是固定的高度,所以根据其是第几条信息,再获取一个list相对页面顶部的高度,就能得到图片相对页面顶部的高度。我这里每个图片(100px)算上间隙(40px)就是140px,只需要获取整个列表相对顶部的高度,就能得到每个图片相对页面顶部的距离。
程序中大概像这样子:

img_data.push({
        index:(num),
        height:list_height+(140)*(num),
        src:data.src,
        loaded:false //定期清理,加载之后的图片信息进行清除,降低内存使用 
      })

视区的检测

图片是否落在用户视区,需要用到以下高度:

  1. height1:document.body.scrollTop:浏览器滚动的高度
  2. height2:document.body.clientHeight:可视区域的高度
  3. height3:node.height:也就是之前获取到的元素相对页面顶部的高度(并不是相对可视区域的顶部)
    当height3>heihgt1且height3<height2+height1的时候,可以认为这个元素是出现在用户视区的,从而将img_data的src赋值给这个块的img标签,当图片加载好之后,opacity配合transition实现动态的浮现(据说,人感觉这样加载的速度更快)。这一块大致的代码如下:
function lazy_load(){
var height1 = document.body.scrollTop+document.body.clientHeight;
  img_data.forEach(function(item){
    if(!item.loaded && item.height>document.body.scrollTop-100 && item.height < height1){
      var img = document.querySelector("img[img-index='"+item.index+"']");
//选择该图片
      if(img){
        img.src = item.src;
        item.loaded = true; //下面对img_data进行filter的函数,减少内存消耗
        img.onload = function(){
          img.style.opacity = 1;//配合transition可以实现一个渐入的效果
        }
        img.onerror = function(){
          img.style.opacity = 1;
          img.src = '/failed.jpg';//加载失败,
        }
      }
    }
  img_data = img_data.filter(function(item){
    return !item.loaded;
  })
}

滚动函数的绑定

直接将上述函数和window.onscroll进行绑定是不太理想的,因为滚动函数的触发频率很高,而视区的检测如果每次滚动都进行检测,那么,一方面造成性能上的损失,一方面,似乎所有的图片都能被检测到出现在了视区,从而导致所有的图片都会被加载,并没有起到懒加载的作用。所以在这里,我使用了函数消抖,原理也不难,网上的实现很多,这里给出我的实现:

method.debounce = function(func,delay){
  var timer;
  return function(){
    var args = arguments;
    var context = this;
    clearTimeout(timer);
    timer = setTimeout(function(){
      func.apply(this,args);
    },delay);
  }
}

和上述lazy_load结合,进行绑定,代码如下:

var lazy_event = method.debounce(lazy_load,500);//此处500ms可以适当缩小
method.addevent(window,'scroll',lazy_event);

和消抖函数结合之后,用户的滚动不会触发lazy_load,只有当用户停止滚动才会执行lazy_load,从而达到图片懒加载的效果。

总结

这次无限滚动,我实现了两种方案:预加载与图片懒加载,配合消抖和节流以及缓存,能够很好的提升页面性能。希望面试的时候能用上吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,727评论 1 92
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,424评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 昨夜 雨声阵阵,寒风瑟瑟 雷雨交加、闪电轰鸣,让人颤栗害怕 冷气逼人,让人感觉冷是从心中钻出来的! 这样的夜 最适...
    流年时光_fe16阅读 536评论 1 2
  • 《坚持一定就有收获!》 2017年 3月19日 星期日 晴今天是读经二年零342天,我的日记大楼盖到1...
    66e1ba940d65阅读 306评论 0 0