日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
從“圖片預(yù)加載”認(rèn)識(shí)代理設(shè)計(jì)模式

本文轉(zhuǎn)載自微信公眾號(hào)「DYBOY」,作者DYBOY。轉(zhuǎn)載本文請(qǐng)聯(lián)系DYBOY公眾號(hào)。

專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)雙江免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了成百上千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

在現(xiàn)代前端優(yōu)化中,圖片預(yù)加載是一種常見的優(yōu)化方法,預(yù)加載的背后是設(shè)計(jì)模式中代理模式的應(yīng)用。

代理模式是為一個(gè)對(duì)象提供一個(gè)代用品或占位符,以便控制對(duì)該對(duì)象的訪問(wèn)。

當(dāng)我們需要獲取某個(gè)對(duì)象的方法或?qū)傩缘臅r(shí)候,由于權(quán)限等限制無(wú)法獲取,然后通過(guò)一個(gè)有權(quán)限的代理對(duì)象轉(zhuǎn)發(fā)我們的獲取請(qǐng)求,代理對(duì)象可對(duì)請(qǐng)求預(yù)處理,同時(shí)在返回結(jié)果的時(shí)候也可以做處理。

生活中的例子:代購(gòu)、網(wǎng)絡(luò)代理、老板秘書等

一、代理模式分類

代理模式細(xì)分有:

  • 虛擬代理:將開銷大的對(duì)象延遲到需要時(shí)才創(chuàng)建
  • 緩存代理:為開銷大的運(yùn)算結(jié)果提供緩存
  • 保護(hù)代理:用于對(duì)象應(yīng)該有不同訪問(wèn)權(quán)限的情況
  • 防火墻代理:控制網(wǎng)絡(luò)資源的訪問(wèn),保護(hù)主機(jī)不被入侵
  • 遠(yuǎn)程代理:為一個(gè)對(duì)象在不同的地址控件提供局部代表
  • 智能引用代理:取代了簡(jiǎn)單的指針,在訪問(wèn)對(duì)象執(zhí)行一些附加操作,比如計(jì)算一個(gè)對(duì)象的引用次數(shù)
  • 寫時(shí)復(fù)制代理:通常用于復(fù)制一個(gè)龐大對(duì)象的情況,延遲對(duì)象復(fù)制過(guò)程,當(dāng)對(duì)象需要真正修改時(shí)才進(jìn)行復(fù)制操作

保護(hù)代理的主要用途就是權(quán)限控制了,但是在 JavaScript 中并不容易實(shí)現(xiàn)保護(hù)代理,因?yàn)闊o(wú)法判斷訪問(wèn)對(duì)象的來(lái)源。

而在 JavaScript 中常用有虛擬代理和緩存代理。

二、虛擬代理實(shí)現(xiàn)圖片預(yù)加載

在例如一些多圖的購(gòu)物網(wǎng)站(淘寶、京東等),都使用了圖片預(yù)加載的技術(shù)。如果直接給 img 標(biāo)簽設(shè)置 src 的值,由于圖片資源過(guò)大或者用戶網(wǎng)絡(luò)環(huán)境不佳,就會(huì)出現(xiàn)一個(gè)長(zhǎng)時(shí)間白屏,以及圖片至上而下的分段加載的情況,用戶體驗(yàn)不好,因此,常見的做法是用一張 Loading 小圖占位,等待實(shí)際需要加載的圖片加載完成后,再將 Loading 小圖替換成實(shí)際的圖片。

比如一個(gè)下載圖片,并將 img 標(biāo)簽 append 到 HTML 中,同時(shí)提供 setSrc(src) 方法用于設(shè)置圖片資源鏈接方法的“本體對(duì)象”實(shí)現(xiàn)如下:

  
 
 
 
  1. var MyImage = (function() {
  2.   var imgNode = document.createElement('img');
  3.   document.body.appendChild(imgNode);
  4.   return {
  5.     setSrc: function(src) {
  6.       imgNode.src = src;
  7.     }
  8.   }
  9. })();

使用:

  
 
 
 
  1. MyImage.setSrc('http://p1.qhimg.com/bdr/__85/t0156672fda5bb4b5d3.jpg')

在弱網(wǎng)環(huán)境下的效果:

弱網(wǎng)圖片下載體驗(yàn)效果

有個(gè)長(zhǎng)時(shí)間的白屏,用戶體驗(yàn)不太友好,為此引入一個(gè) ProxyImage 代理對(duì)象,通過(guò)該代理對(duì)象,在圖片真正被加載完成之前,頁(yè)面中顯示一個(gè) loading 動(dòng)圖來(lái)提示用戶圖片正在加載中

  
 
 
 
  1. var ProxyImage = (function() {
  2.   var img = new Image();
  3.   img.onload = function() {
  4.     MyImage.setSrc(this.src);
  5.   }
  6.   return {
  7.     setSrc: function(src) {
  8.       MyImage.setSrc('./loading.gif');
  9.       img.src = src;
  10.     }
  11.   }
  12. })();

使用方法:

  
 
 
 
  1. ProxyImage.setSrc('http://p1.qhimg.com/bdr/__85/t0156672fda5bb4b5d3.jpg');

效果:

預(yù)加載下的體驗(yàn)效果

可以看到我們?cè)跊](méi)有修改原有的 MyImage 對(duì)象,通過(guò)代理對(duì)象 ProxyImage 給其增加了預(yù)加載的能力。

實(shí)際上,我們可以不用代理就能實(shí)現(xiàn)預(yù)加載圖片,為什么還要這么做吶?在對(duì)象設(shè)計(jì)的原則中有個(gè)“單一職責(zé)原則”。如果一個(gè)對(duì)象承擔(dān)了多項(xiàng)職責(zé),那么對(duì)象就會(huì)變得較大,引起它變化的原因就可能有多個(gè),那么職責(zé)的耦合度就比較高,會(huì)導(dǎo)致脆弱和低內(nèi)聚的設(shè)計(jì),當(dāng)變化發(fā)生時(shí),設(shè)計(jì)可能會(huì)遭到意外的破壞。

單一職責(zé)原則值得是,一個(gè)類應(yīng)該僅有一個(gè)引起它變化的原因。職責(zé)被定義為“引起變化的原因”。

上述的做法,MyImage 僅用于添加設(shè)置 img 節(jié)點(diǎn),ProxyImage 賦予了 MyImage 預(yù)加載的能力,并且對(duì)于 MyImage 對(duì)象不會(huì)有任何侵入性的修改,符合開放封閉原則。如果有一天網(wǎng)絡(luò)足夠快了,我們只需要改為請(qǐng)求本體而不是代理對(duì)象即可。不過(guò)要實(shí)現(xiàn)這種低成本改造,還得保證“代理和本體接口的一致性”。

保證代理和本地的一致性有如下好處:

  • 用戶可以放心地請(qǐng)求代理,他只關(guān)心是否能夠獲取想要的結(jié)果;
  • 在任何使用本體的地方都可以替換成代理。

三、緩存代理節(jié)省計(jì)算開銷

緩存代理為一些開銷大的運(yùn)算結(jié)果提供臨時(shí)存儲(chǔ),類比于“查表法”。在之前講《從閉包和高階函數(shù)初探JS設(shè)計(jì)模式》中有講到“緩存計(jì)算”概念,主要是借助“閉包”來(lái)實(shí)現(xiàn)臨時(shí)存儲(chǔ)。

首先是一個(gè)基本的乘積函數(shù):

  
 
 
 
  1. var mult = function () {
  2.   var a = 1;
  3.   for(var i =0; i< arguments.length; i++) {
  4.     a = a * arguments[i];
  5.   }
  6.   return a;
  7. }
  8. mult(1,2,3) // 6

我們都知道乘法的計(jì)算開銷比較大,如果涉及到頻繁密集型的計(jì)算,那么對(duì)于計(jì)算機(jī)的計(jì)算性能要求就比較高,那么思考是否可以用存儲(chǔ)換時(shí)間?因此想到了將計(jì)算過(guò)的算式緩存,下次再遇到直接獲取值的方式,同樣考慮到職責(zé)單一設(shè)計(jì)原則,所以我們可以創(chuàng)建一個(gè)緩存代理函數(shù):

  
 
 
 
  1. const ProxyMult = (function () {
  2.   const cache = {};
  3.   return function () {
  4.     const args = [].join.call(arguments, ',');
  5.     if (args in cache) {
  6.       return cache[args];
  7.     }
  8.     let sum = 1;
  9.     for (let i = 0; i < arguments.length; i++) {
  10.       sum = sum * arguments[i];
  11.     }
  12.     return cache[args] = sum;
  13.   }
  14. })();
  15. ProxyMult(1, 2, 3, 4);

這樣我們就為乘積函數(shù)提供了緩存能力,下次遇到相同算式,就可以不通過(guò)計(jì)算,類似查表方式拿到計(jì)算結(jié)果,再一定程度上提升了計(jì)算性能。

同理,Ajax 請(qǐng)求是一個(gè)耗時(shí)的 IO 操作,比如我們獲取用戶 uid=1 的信息需要 Ajax 請(qǐng)求一次,在一定時(shí)間內(nèi),當(dāng)下一次再獲取 uid=1 用戶的信息的時(shí)候,我們沒(méi)必要再去請(qǐng)求一次,因?yàn)橛脩舻幕A(chǔ)信息并不是頻繁更新的,此時(shí)我們可以通過(guò)緩存方式拿到上一次獲取到的用戶信息,節(jié)省網(wǎng)絡(luò)帶寬資源,降低網(wǎng)絡(luò)異常帶來(lái)出錯(cuò)的可能性。

在一些場(chǎng)景下我們可以嘗試自行封裝 Ajax 請(qǐng)求,可自行維護(hù)緩存策略。

四、總結(jié)

代理模式的應(yīng)用場(chǎng)景像是一種賦能,保證代理和本體接口一致性的情況下,比如給圖片加載增加“預(yù)加載”能力,給乘法計(jì)算增加“緩存”能力。

“青出于藍(lán)而勝于藍(lán)”似乎是一個(gè)不錯(cuò)的解釋。


標(biāo)題名稱:從“圖片預(yù)加載”認(rèn)識(shí)代理設(shè)計(jì)模式
標(biāo)題URL:http://www.dlmjj.cn/article/dhdhgch.html