代理模式是爲一個對象提供一個代用品或佔位符,以便控制對它的訪問。
實例一、圖片懶加載
圖片懶加載是指,圖片的加載應該在頁面全部加載完後,再去加載。這樣能夠提高加載的速度和網頁的體驗性。實際操作就是,將原來網頁的src獨立出來,將原來圖片使用一個loading.gif代替,然後在js裏面手動創建個img去加載這個src,當加載完後把src替換就可以了。
var myImage=(function(){
var imgNode=document.createEvent('img');
document.body.appendChild(imgNode);
return{
setSrc : function(src){
imgNode.src=src;
}
}
})();
var proxyImage=(function(){
var img = new Image;
img.onload = function(){
myImage.setSrc(this.src);
}
return {
setSrc : function(){
myImage.setSrc('/images/loading.gif');
img.src = src;
}
}
})();
proxyImage.setSrc('real.jpg');
上面的代碼,我們通過proxyImage間接的訪問myImage。proxyImage控制了用戶對myImage的訪問,並且在此過程中加入一些額外的操作,比如在真正加載完圖片之前,先把img的節點的src設置爲一張本地的loading圖片。
保護代理和虛擬代理
這其實很好理解,保護代理就是起到保護作用,用來過濾掉一下不必要的請求,將真正需要的遞給本體。
虛擬代理和函數節流的思想是一樣的,將用戶對性能的rape的傷害降低到最低。就像送快遞一樣,一件一件的送,這個公司是不是傻~ 所以爲了生存,快遞公司會當物品積攢到一定程度後纔會讓快遞哥騎着小電驢穿梭在神州大地上。
虛擬代理
上面的保護代理闡述了怎樣去拒絕請求,而虛擬代理的原則是收集請求(來者不拒). 他的出發點和保護代理的是一樣的,都是爲了節省請求的開支。
比如: 一個在線的編輯器,他是怎樣同步你的內容呢?不會是,你內容一改變就發送一起請求同步吧。這個想法顯然不切實際。如果這樣,我每天沒事都會打開這個編輯器,把asfdsafdsafsad…在裏面敲上幾分鐘。保證分分鐘弄死他的服務器。所以一般,我們會使用虛擬代理來接受你的請求。
就算你手速再快,我就只能2s發一次。 但這只是一個比較簡單的實例。如果大家感興趣可以研究一下,作業部落這個編輯器,他這個markdown同步和體驗交互式我迄今爲止用過應該算最好的一個了吧~
緩存代理
這個應該是應用最多的一個代理方式了,這種方式能夠真正解決運算時間問題,網絡不暢問題,離線問題。
搬一個例子過來吧。
計算乘積問題
function fb(num){ //斐波那契函數,超級耗內存
if(num<=1){
return 1;
}
return num*fb(--num)
}
//緩存代理出場了
var cProxy = (function(){
var cache = {};
return function(num){
if(cache[num]){
console.log(`this is cache ${cache[num]}`);
return cache[num];
}
return cache[num] = fb(num);
}
})();
//測試
console.log(cProxy(4)); //24
cProxy(4); //"this is cache 24"
恩,完美。 我們知道階乘是比較累的一個計算方法,如果某天你的leader需要你計算很多次fb(2000)。用戶的電腦也吃不消啊,所以爲了體驗,緩存代理是你百分百女友,好好珍惜。
當然,緩存代理並不只有這一點用途,比如需要重複獲取網頁中大部分數據的時候,就可以考慮使用緩存代理。前端工作者,99.9999%的應該都會遇見分頁的問題(請不要告訴我你的分頁是同步方式). 當我們點擊一個頁面的時候,獲取後臺的數據,然後再由我恩渲染到頁面上,這是這樣一個流程。 首先,渲染流程可以複用,那數據的複用性該怎麼做呢?
恩,猜到了吧,就是使用cache進行一個緩存,然後如果下次獲取分頁的頁碼一致的話,就可以直接使用該數據了。
//向後臺發請求,獲取當前頁面的數據
// http.getPage(page);
var pageProxy = (function(){
var cache = {};
return function(fn){ //fn作爲處理頁碼數據的函數
var pageData = cache[page];
if(pageData){
return fn(pageData); //返回制定頁碼的數據
}
http.getPage(page) //獲取制定頁碼的數據
.then((data)=>{
cache[page] = data; //存放數據
fn(data);
})
}
})();
最後再說一句吧,由於代理寫起來需要更多的邏輯和代碼,如果你的產經沒有什麼需求的話,不用代理也是行得通的。還有就是,用不用代理和你原來的本體執行的業務邏輯是完全分開的,即,如果後期產經有什麼需求,或者你對自己的代碼不滿意,重構的時候,再添加代理,這種方式也是很推薦的。