当前位置: 首页 > news >正文

javascript设计模式实践之代理模式--图片预加载

图片的预加载就是在加载大图片前,先显示一个loading.gif,就算在网络比较慢的时候也能让人知道正在加载,总比啥反应都没有强。

下面这段代码就是预加载的一个简单的实现,假设先不处理加载图片时的onError,onAbort,超时的问题。

只关注代码的结构。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <button id='btnLoadImg'>加载图片</button>
        <br>
        <div id='imgContainer'>
        </div>
        <br>

        <script type='text/javascript' src="./jquery-1.11.3.min.js"></script>
        <script type='text/javascript'>
            $(document).ready(function(){
                $('#btnLoadImg').bind('click', doLoadImg);
            });

            function doLoadImg(){

                var eleImg = createImgElement();
                document.getElementById('imgContainer').appendChild(eleImg);

                loadImg(eleImg, 'http://img.wanchezhijia.com/A/2015/3/20/17/11/de63f77c-f74f-413a-951b-5390101a7d74.jpg');
            }

            //创建img标签
            //这里用自执行函数加一个闭包,是为了可以创建多个id不同的img标签。
            var createImgElement = (function(){
                var index = 0;

                return function() {
                    var eleImg = document.createElement('img');
                    eleImg.setAttribute('width', '200');
                    eleImg.setAttribute('heght', '150');
                    eleImg.setAttribute('id', 'img' + index++);
                    return eleImg;
                };
            })();

            //预加载图片
            //给img标签设一个加载图片,通过Image对象预先加载实际图片加载完成后设到img标签上
            function loadImg(img, src) {
                var imgCache = new Image();
                imgCache.onload = function(){
                    img.src = this.src;
                };

                img.src = 'loading.gif';
                imgCache.src = src;
            }

        </script>
    </body>
</html>

 

以下预加载的代码功能上是满足了,但是它的职责包含了预加载和加载两个职责,违反了“单一职责原则”。所谓的职责就是“会发生的变化”,如果网速的问题不再是问题或者加载的图片的分辨率被控制在很小的时候等,需要去掉预加载的功能,这时候就要修改loadImg的代码,就要重新跑所有相关的测试,即违反了“开闭原则”,又增加测试工作。

            function loadImg(img, src) {
                var imgCache = new Image();
                imgCache.onload = function(){
                    img.src = this.src;
                };

                img.src = 'loading.gif';
                imgCache.src = src;
            }

 

加载和预加载其实就是代理模式的一种,代理模式可以理解成,你会开车但是因为某种原因只能找人代理开车,因为不了解MM的喜好找人代理送花。

将预加载功能改成代理模式可以理解成:本体先显示个门面,找代理去加载,加载完了,告诉本体,本体把图片贴上去就行了。

既然如此,本体的职责就很简单了,就往门面上贴。

加载本体函数:

            function loadImg(img, src) {
                img.src = src;
            }

 

做一个预加载代理函数:

            function loadImgProxy(img, src){
                var imgCache = new Image();
                imgCache.onload = function(){
                    loadImg(img, this.src);
                };

                loadImg(img, 'loading.gif');
                imgCache.src = src;
            }

在代理函数中,先让本体加载loading.gif,等大图加载完了再让本体加载实际图片。

代理还是和本体函数的接口参数是一致的,职责分的比较清晰,如果到时候要把预加载去掉,也不需要修改本体和代理的代码,只需要在调用的地方把代理的名字换成本体的名字即可。

可以适当的把代理函数改一下,可以让其适应加载多个图片的场景,其实就是做一个闭包,把缓存Image对象变成私有即可:

            var loadImgProxy = (function(){
                var imgCache = new Image();

                return function(img, src){
                    imgCache.onload = function(){
                        loadImg(img, this.src);
                    };

                    loadImg(img, 'loading.gif');
                    imgCache.src = src;
                };
            })();

 

修改后的完整代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <button id='btnLoadImg'>加载图片</button>
        <br>
        <div id='imgContainer'>
        </div>
        <br>

        <script type='text/javascript' src="./jquery-1.11.3.min.js"></script>
        <script type='text/javascript'>
            $(document).ready(function(){
                $('#btnLoadImg').bind('click', doLoadImg);
            });

            function doLoadImg(){

                var eleImg = createImgElement();
                document.getElementById('imgContainer').appendChild(eleImg);

//使用代理函数进行加载
//如果某一天不需要预加载了,就把loadImgProxy换成loadImg即可 loadImgProxy(eleImg,
'http://img.wanchezhijia.com/A/2015/3/20/17/11/de63f77c-f74f-413a-951b-5390101a7d74.jpg'); } //创建img标签 //这里用自执行函数加一个闭包,是为了可以创建多个id不同的img标签。 var createImgElement = (function(){ var index = 0; return function() { var eleImg = document.createElement('img'); eleImg.setAttribute('width', '200'); eleImg.setAttribute('heght', '150'); eleImg.setAttribute('id', 'img' + index++); return eleImg; }; })();
//加载图片本体函数 function loadImg(img, src) { img.src = src; }
//加载图片代理函数
var loadImgProxy = (function(){ var imgCache = new Image(); return function(img, src){ imgCache.onload = function(){ loadImg(img, this.src); }; loadImg(img, 'loading.gif'); imgCache.src = src; }; })(); </script> </body> </html>

 

相关文章:

  • 数据库开发基本操作-Microsoft SQL Server Management Studio Express下载和安装
  • Extract+datapump+replicat 测试
  • Git 菜鸟变大神 (四)Github 创建远程仓库以及关联本地仓库
  • Flash移动开发的一本好书AndroidIOS
  • ::before和::after 常见的用法
  • 跟我一起学习C++虚函数--第二篇
  • MySQL优化order by导致的 using filesort
  • 管理日志-原创理论工具--技能方格图
  • objective-c系列-NSMutableString
  • MySQL 数据库开发规范
  • 20 种提升网页速度的技巧
  • xdebug代码调试工具
  • AngularJS Toaster
  • 静态网站生成器将会成为下一个大热门
  • 二维数组举例
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • Apache的80端口被占用以及访问时报错403
  • canvas 高仿 Apple Watch 表盘
  • CSS3 变换
  • css系列之关于字体的事
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • Magento 1.x 中文订单打印乱码
  • Python 反序列化安全问题(二)
  • vue.js框架原理浅析
  • vue中实现单选
  • Yeoman_Bower_Grunt
  • 从重复到重用
  • 欢迎参加第二届中国游戏开发者大会
  • 将 Measurements 和 Units 应用到物理学
  • 爬虫模拟登陆 SegmentFault
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 通过几道题目学习二叉搜索树
  • 通信类
  • 《天龙八部3D》Unity技术方案揭秘
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • # 达梦数据库知识点
  • (C#)获取字符编码的类
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (四) 虚拟摄像头vivi体验
  • (四)Android布局类型(线性布局LinearLayout)
  • (未解决)macOS matplotlib 中文是方框
  • (一)基于IDEA的JAVA基础10
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • .bat批处理(十一):替换字符串中包含百分号%的子串
  • .DFS.
  • .NET 4.0中使用内存映射文件实现进程通讯
  • .net core 调用c dll_用C++生成一个简单的DLL文件VS2008
  • .net redis定时_一场由fork引发的超时,让我们重新探讨了Redis的抖动问题
  • .NetCore Flurl.Http 升级到4.0后 https 无法建立SSL连接
  • .NET连接数据库方式
  • .net流程开发平台的一些难点(1)
  • .Net中的集合
  • @GetMapping和@RequestMapping的区别