《JavaScript設計模式與開發實踐》模式篇(3)—— 代理模式
假設當 A 在心情好的時候收到花,小明表白成功的機率有 60%,而當 A 在心情差的時候收到花,小明表白的成功率無限趨近於 0。 小明跟 A 剛剛認識兩天,還無法辨別 A 什麼時候心情好。如果不合時宜地把花送給 A,花 被直接扔掉的可能性很大,這束花可是小明吃了 7 天泡麵換來的。 但是 A 的朋友 B 卻很瞭解 A,所以小明只管把花交給 B,B 會監聽 A 的心情變化,然後選 擇 A 心情好的時候把花轉交給 A,程式碼實現:
var Flower = function(){}; var xiaoming = { sendFlower: function( target){ var flower = new Flower(); target.receiveFlower( flower ); } }; var B = { receiveFlower: function( flower ){ A.listenGoodMood(function(){ var flower = new Flower(); A.receiveFlower( flower ); }); } }; var A = { receiveFlower: function( flower ){ // 監聽 A 的好心情 console.log( '收到花 ' + flower ); }, listenGoodMood: function( fn ){ setTimeout(function(){ // 假設 10 秒之後 A 的心情變好 fn(); }, 10000 ); } }; xiaoming.sendFlower( B ); 複製程式碼
由上面的例子可以引出兩種代理模式
- 保護代理 代理 B 可以幫助 A 過濾掉一些請求,比如送花的人中年齡太大的或者沒有寶馬的,這種請求就可以直接在代理 B 處被拒絕掉
- 虛擬代理 假設現實中的花價格不菲,導致在程式世界裡,new Flower 也是一個代價昂貴的操作, 那麼我們可以把 new Flower 的操作交給代理 B 去執行,代理 B 會選擇在 A 心情好時再執行 new Flower
應用場景
- 虛擬代理實現圖片預載入
var myImage = (function(){ var imgNode = document.createElement( '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( src ){ myImage.setSrc( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' ); img.src = src; } } })(); proxyImage.setSrc('http://imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' ); 複製程式碼
- 虛擬代理合並HTTP請求 假設我們在做一個檔案同步的功能,當我們選中一個 checkbox 的時候,它對應的檔案就會被同 步到另外一臺備用伺服器上面。當一次選中過多時,會產生頻繁的網路請求。將帶來很大的開銷。可以通過一個代理函式 proxySynchronousFile 來收集一段時間之內的請求, 最後一次性發送給伺服器
var synchronousFile = function( id ){ console.log( '開始同步檔案,id 為: ' + id ); }; var proxySynchronousFile = (function(){ var cache = [], // 儲存一段時間內需要同步的 ID timer; // 定時器 return function( id ){ cache.push( id ); if ( timer ){ // 保證不會覆蓋已經啟動的定時器 return; } timer = setTimeout(function(){ synchronousFile( cache.join( ',' ) ); clearTimeout( timer ); // 清空定時器 timer = null; cache.length = 0; // 清空 ID 集合 }, 2000 ); }// 2 秒後向本體傳送需要同步的 ID 集合 })(); var checkbox = document.getElementsByTagName( 'input' ); for ( var i = 0, c; c = checkbox[ i++ ]; ){ c.onclick = function(){ if ( this.checked === true ){ proxySynchronousFile( this.id ); } } }; 複製程式碼
ofollow,noindex">《JavaScript/">JavaScript設計模式與開發實踐》基礎篇(1)—— this、call 和 apply
《JavaScript設計模式與開發實踐》基礎篇(2)—— 閉包和高階函式