当前位置: 首页 > 科技观察

从“图片预加载”认识代理设计模式

时间:2023-03-12 18:36:37 科技观察

转载本文请联系DYBOY公众号。在现代前端优化中,图片预加载是一种常见的优化方法。预加载的背后是代理模式在设计模式中的应用。代理模式是为对象提供替代品或占位符,以控制对该对象的访问。当我们需要获取一个对象的方法或属性时,由于权限等限制无法获取,然后通过一个有权限的代理对象转发我们的请求。代理对象可以预处理请求并返回结果。可以做加工。生活中的例子:采购代理、网络代理、老板秘书等。一、代理模式分类代理模式细分包括:虚拟代理:将昂贵的对象延迟到需要的时候再创建缓存代理:为昂贵的计算结果提供缓存保护Proxy:当对象使用时应该有不同的访问权限FirewallProxy:控制对网络资源的访问并保护主机免受入侵RemoteProxy:提供一个对象在不同地址的本地表示ControlSmartReferenceProxy:替换简单的指针,对访问对象执行一些额外的操作,比如计算对对象的引用数。Copy-on-writeproxy:通常用于复制一个巨大的对象,延迟对象的复制过程,只在对象真正需要修改时才执行复制操作。保护代理的主要目的是权限控制,但是在JavaScript中实现保护代理并不容易,因为无法判断访问对象的来源。在JavaScript中,常用的有虚拟代理和缓存代理。2、虚拟代理实现图像预加载。比如一些图片比较多的购物网站(淘宝、京东等)都采用了图片预加载技术。如果直接给img标签设置src值,由于图片资源大或者用户网络环境差,会出现长长的白屏,图片会从上到下分段加载,用户体验不会好。因此,一种常见的做法是用一个小的Loading图片占位,等待实际图片加载完毕,再用实际图片替换Loading图片。比如一个下载图片,在HTML中附加img标签,提供setSrc(src)方法设置图片资源链接方法的“本体对象”,实现如下:varMyImage=(function(){varimgNode=document.createElement('img');document.body.appendChild(imgNode);return{setSrc:function(src){imgNode.src=src;}}})();use:MyImage.setSrc('http://p1.qhimg.com/bdr/__85/t0156672fda5bb4b5d3.jpg')弱网环境下:弱网下载图片体验效果长白屏,用户体验不是很友好。为此,引入了一个ProxyImage代理对象,通过这个代理对象,在图片真正加载之前,在页面上显示加载动画,提醒用户图片正在加载中varProxyImage=(function(){varimg=newImage();img.onload=function(){MyImage.setSrc(this.src);}return{setSrc:function(src){MyImage.setSrc('./loading.gif');img.src=src;}}})();使用方法:ProxyImage.setSrc('http://p1.qhimg.com/bdr/__85/t0156672fda5bb4b5d3.jpg');效果:预加载下的体验效果可以看到我们没有修改原来的MyImage对象,而是通过代理对象ProxyImage的能力给它添加了预加载的。其实不用代理我们也可以实现预加载图片,为什么要这么做呢?对象设计原则中有一个“单一职责原则”。如果一个对象承担了多个职责,这个对象就会变大,并且它的变化可能有多种原因,那么职责的耦合度就会比较高,这就会导致一个脆弱的、低内聚的设计。发生这种情况时,设计可能会意外损坏。单一职责原则值得一提的是,一个类应该只有一个改变它的理由。职责被定义为“变化的原因”。上述做法中,MyImage只是用来添加和设置img节点,而ProxyImage赋予了MyImage预加载的能力,不会对MyImage对象进行侵入式修改,符合开放封闭原则。如果有一天网络足够快,我们只需要换成请求体,而不是代理对象。但是,要实现这种低成本的改造,就需要保证“代理与本体接口的一致性”。保证代理和本地的一致性有以下好处:用户可以放心地请求代理,他只关心能不能得到想要的结果;任何使用本体的地方都可以被代理替换。3、缓存代理节省了计算开销。缓存代理为一些昂贵的计算结果提供临时存储,类似于“查表法”。在上一讲《从闭包和高阶函数初探JS设计模式》中,提到了“缓存计算”的概念,主要是利用“闭包”来实现暂存。第一个是基本的乘积函数:varmult=function(){vara=1;for(vari=0;i