源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

JavaScript前端图片加载管理器imagepool使用详解

  • 时间:2020-02-22 07:14 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:JavaScript前端图片加载管理器imagepool使用详解
[b]前言[/b]       imagepool是一款管理图片加载的JS工具,通过imagepool可以控制图片并发加载个数。       对于图片加载,最原始的方式就是直接写个img标签,比如:<img src="图片url" />。       经过不断优化,出现了图片延迟加载方案,这回图片的URL不直接写在src属性中,而是写在某个属性中,比如:<img src="" data-src="图片url" />。这样浏览器就不会自动加载图片,等到一个恰当的时机需要加载了,则用js把data-src属性中的url放到img标签的src属性中,或者读出url后,用js去加载图片,加载完成后再设置src属性,显示出图片。       这看起来已经控制的很好了,但依然会有问题。       虽然能做到只加载一部分图片,但这一部分图片,仍然可能是一个比较大的数量级。       这对于PC端来说,没什么大不了,但对于移动端,图片并发加载数量过多,极有可能引起应用崩溃。       因此我们迫切需要一种图片缓冲机制,来控制图片加载并发。类似于后端的数据库连接池,既不会创建过多连接,又能充分复用每一个连接。       至此,imagepool诞生了。 [b] 拙劣的原理图[/b] [img]http://files.jb51.net/file_images/article/201412/201412291008452.png[/img]   [b]使用说明[/b]      首先要初始化连接池:  var imagepool = initImagePool(5);      initImagePool 是全局方法,任何地方都可以直接使用。作用是创建一个连接池,并且可以指定连接池的最大连接数,可选,默认为5。      在同一个页面中,多次调用initImagePool均返回同一个核心实例,永远是第一个,有点单例的感觉。比如:
[u]复制代码[/u] 代码如下:
 var imagepool1 = initImagePool(3);  var imagepool2 = initImagePool(7);
     此时imagepool1和imagepool2的最大连接数均为3,内部使用的是同一个核心实例。注意,是内部的核心相同,并不是说imagepool1 === imagepool2。      初始化之后,就可以放心大胆的加载图片了。      最简单的调用方法如下:
[u]复制代码[/u] 代码如下:
 var imagepool = initImagePool(10);  imagepool.load("图片url",{      success: function(src){          console.log("success:::::"+src);      },      error: function(src){          console.log("error:::::"+src);      }  });
     直接在实例上调用load方法即可。      load方法有两个参数。第一个参数是需要加载的图片url,第二个参数是各种选项,包含了成功、失败的回调,回调时会传入图片url。      这样写只能传入一张图片,因此,也可以写成如下形式:
[u]复制代码[/u] 代码如下:
 var imagepool = initImagePool(10);  imagepool.load(["图片1url","图片2url"],{      success: function(src){          console.log("success:::::"+src);      },      error: function(src){          console.log("error:::::"+src);      }  });
     通过传入一个图片url数组,就可以传入多个图片了。      每一个图片加载成功(或失败),都会调用success(或error)方法,并且传入对应的图片url。      但有时候我们并不需要这样频繁的回调,传入一个图片url数组,当这个数组中所有的图片都处理完成后,再回调就可以了。      只需加一个选项即可:
[u]复制代码[/u] 代码如下:
 var imagepool = initImagePool(10);  imagepool.load(["图片1url ","图片2url "],{      success: function(sArray, eArray, count){          console.log("sArray:::::"+sArray);          console.log("eArray:::::"+eArray);          console.log("count:::::"+count);      },      error: function(src){          console.log("error:::::"+src);      },      once: true  });
     通过在选项中加一个once属性,并设置为true,即可实现只回调一次。      这一次回调,必然回调success方法,此时error方法是被忽略的。      此时回调success方法,不再是传入一个图片url参数,而是传入三个参数,分别为:成功的url数组、失败的url数组、总共处理的图片个数。      此外,还有一个方法可以获取连接池内部状态:
[u]复制代码[/u] 代码如下:
 var imagepool = initImagePool(10);  console.log(imagepool.info());
     通过调用info方法,可以得到当前时刻连接池内部状态,数据结构如下:      Object.task.count 连接池中等待处理的任务数量      Object.thread.count 连接池最大连接数      Object.thread.free 连接池空闲连接数        建议不要频繁调用此方法。      最后需要说明的是,如果图片加载失败,最多会尝试3次,如果最后还是加载失败,才回调error方法。尝试次数可在源码中修改。      最最后再强调一下,读者可以尽情的往连接池中push图片,完全不必担心并发过多的问题,imagepool会有条不絮的帮你加载这些图片。      最最最后,必须说明的是,imagepool理论上不会降低图片加载速度,只不过是平缓的加载。 源码
[u]复制代码[/u] 代码如下:
(function(exports){     //单例     var instance = null;     var emptyFn = function(){};     //初始默认配置     var config_default = {         //线程池"线程"数量         thread: 5,         //图片加载失败重试次数         //重试2次,加上原有的一次,总共是3次         "try": 2     };     //工具     var _helpers = {         //设置dom属性         setAttr: (function(){             var img = new Image();             //判断浏览器是否支持HTML5 dataset             if(img.dataset){                 return function(dom, name, value){                     dom.dataset[name] = value;                     return value;                 };             }else{                 return function(dom, name, value){                     dom.setAttribute("data-"+name, value);                     return value;                 };             }         }()),         //获取dom属性         getAttr: (function(){             var img = new Image();             //判断浏览器是否支持HTML5 dataset             if(img.dataset){                 return function(dom, name){                     return dom.dataset[name];                 };             }else{                 return function(dom, name){                     return dom.getAttribute("data-"+name);                 };             }         }())     };     /**      * 构造方法      * @param max 最大连接数。数值。      */     function ImagePool(max){         //最大并发数量         this.max = max || config_default.thread;         this.linkHead = null;         this.linkNode = null;         //加载池         //[{img: dom,free: true, node: node}]         //node         //{src: "", options: {success: "fn",error: "fn", once: true}, try: 0}         this.pool = [];     }     /**      * 初始化      */     ImagePool.prototype.initPool = function(){         var i,img,obj,_s;         _s = this;         for(i = 0;i < this.max; i++){             obj = {};             img = new Image();             _helpers.setAttr(img, "id", i);             img.onload = function(){                 var id,src;                 //回调                 //_s.getNode(this).options.success.call(null, this.src);                 _s.notice(_s.getNode(this), "success", this.src);                 //处理任务                 _s.executeLink(this);             };             img.onerror = function(e){                 var node = _s.getNode(this);                 //判断尝试次数                 if(node.try < config_default.try){                     node.try = node.try + 1;                     //再次追加到任务链表末尾                     _s.appendNode(_s.createNode(node.src, node.options, node.notice, node.group, node.try));                 }else{                     //error回调                     //node.options.error.call(null, this.src);                     _s.notice(node, "error", this.src);                 }                 //处理任务                 _s.executeLink(this);             };             obj.img = img;             obj.free = true;             this.pool.push(obj);         }     };     /**      * 回调封装      * @param node 节点。对象。      * @param status 状态。字符串。可选值:success(成功)|error(失败)      * @param src 图片路径。字符串。      */     ImagePool.prototype.notice = function(node, status, src){         node.notice(status, src);     };     /**      * 处理链表任务      * @param dom 图像dom对象。对象。      */     ImagePool.prototype.executeLink = function(dom){         //判断链表是否存在节点         if(this.linkHead){             //加载下一个图片             this.setSrc(dom, this.linkHead);             //去除链表头             this.shiftNode();         }else{             //设置自身状态为空闲             this.status(dom, true);         }     };     /**      * 获取空闲"线程"      */     ImagePool.prototype.getFree = function(){         var length,i;         for(i = 0, length = this.pool.length; i < length; i++){             if(this.pool[i].free){                 return this.pool[i];             }         }         return null;     };     /**      * 封装src属性设置      * 因为改变src属性相当于加载图片,所以把操作封装起来      * @param dom 图像dom对象。对象。      * @param node 节点。对象。      */     ImagePool.prototype.setSrc = function(dom, node){         //设置池中的"线程"为非空闲状态         this.status(dom, false);         //关联节点         this.setNode(dom, node);         //加载图片         dom.src = node.src;     };     /**      * 更新池中的"线程"状态      * @param dom 图像dom对象。对象。      * @param status 状态。布尔。可选值:true(空闲)|false(非空闲)      */     ImagePool.prototype.status = function(dom, status){         var id = _helpers.getAttr(dom, "id");         this.pool[id].free = status;         //空闲状态,清除关联的节点         if(status){             this.pool[id].node = null;         }     };     /**      * 更新池中的"线程"的关联节点      * @param dom 图像dom对象。对象。      * @param node 节点。对象。      */     ImagePool.prototype.setNode = function(dom, node){         var id = _helpers.getAttr(dom, "id");         this.pool[id].node = node;         return this.pool[id].node === node;     };     /**      * 获取池中的"线程"的关联节点      * @param dom 图像dom对象。对象。      */     ImagePool.prototype.getNode = function(dom){         var id = _helpers.getAttr(dom, "id");         return this.pool[id].node;     };     /**      * 对外接口,加载图片      * @param src 可以是src字符串,也可以是src字符串数组。      * @param options 用户自定义参数。包含:success回调、error回调、once标识。      */     ImagePool.prototype.load = function(src, options){         var srcs = [],             free = null,             length = 0,             i = 0,             //只初始化一次回调策略             notice = (function(){                 if(options.once){                     return function(status, src){                         var g = this.group,                             o = this.options;                         //记录                         g[status].push(src);                         //判断改组是否全部处理完成                         if(g.success.length + g.error.length === g.count){                             //异步                             //实际上是作为另一个任务单独执行,防止回调函数执行时间过长影响图片加载速度                             setTimeout(function(){                                 o.success.call(null, g.success, g.error, g.count);                             },1);                         }                     };                 }else{                     return function(status, src){                         var o = this.options;                         //直接回调                         setTimeout(function(){                             o[status].call(null, src);                         },1);                     };                 }             }()),             group = {                 count: 0,                 success: [],                 error: []             },             node = null;         options = options || {};         options.success = options.success || emptyFn;         options.error = options.error || emptyFn;         srcs = srcs.concat(src);         //设置组元素个数         group.count = srcs.length;         //遍历需要加载的图片         for(i = 0, length = srcs.length; i < length; i++){             //创建节点             node = this.createNode(srcs[i], options, notice, group);             //判断线程池是否有空闲             free = this.getFree();             if(free){                 //有空闲,则立即加载图片                 this.setSrc(free.img, node);             }else{                 //没有空闲,将任务添加到链表                 this.appendNode(node);             }         }     };     /**      * 获取内部状态信息      * @returns {{}}      */     ImagePool.prototype.info = function(){         var info = {},             length = 0,             i = 0,             node = null;         //线程         info.thread = {};         //线程总数量         info.thread.count = this.pool.length;         //空闲线程数量         info.thread.free = 0;         //任务         info.task = {};         //待处理任务数量         info.task.count = 0;         //获取空闲"线程"数量         for(i = 0, length = this.pool.length; i < length; i++){             if(this.pool[i].free){                 info.thread.free = info.thread.free + 1;             }         }         //获取任务数量(任务链长度)         node = this.linkHead;         if(node){             info.task.count = info.task.count + 1;             while(node.next){                 info.task.count = info.task.count + 1;                 node = node.next;             }         }         return info;     };     /**      * 创建节点      * @param src 图片路径。字符串。      * @param options 用户自定义参数。包含:success回调、error回调、once标识。      * @param notice 回调策略。 函数。      * @param group 组信息。对象。{count: 0, success: [], error: []}      * @param tr 出错重试次数。数值。默认为0。      * @returns {{}}      */     ImagePool.prototype.createNode = function(src, options, notice, group, tr){         var node = {};         node.src = src;         node.options = options;         node.notice = notice;         node.group = group;         node.try = tr || 0;         return node;     };     /**      * 向任务链表末尾追加节点      * @param node 节点。对象。      */     ImagePool.prototype.appendNode = function(node){         //判断链表是否为空         if(!this.linkHead){             this.linkHead = node;             this.linkNode = node;         }else{             this.linkNode.next = node;             this.linkNode = node;         }     };     /**      * 删除链表头      */     ImagePool.prototype.shiftNode = function(){         //判断链表是否存在节点         if(this.linkHead){             //修改链表头             this.linkHead = this.linkHead.next || null;         }     };     /**      * 导出对外接口      * @param max 最大连接数。数值。      * @returns {{load: Function, info: Function}}      */     exports.initImagePool = function(max){         if(!instance){             instance = new ImagePool(max);             instance.initPool();         }         return {             /**              * 加载图片              */             load: function(){                 instance.load.apply(instance, arguments);             },             /**              * 内部信息              * @returns {*|any|void}              */             info: function(){                 return instance.info.call(instance);             }         };     }; }(this));
以上就是这款特别棒的javascript前端图片加载管理器的使用方法示例,小伙伴们学会使用了吗?
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部