iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 3
0
Modern Web

JS Design Pattern 系列 第 3

JS Design Pattern Day03-代理模式 Proxy

嗨大家好,我是小胖與他快樂夥伴裡的夥伴,是你的夥伴,也是國民的好夥伴,今天是鐵人賽第三天,才第三天..,我為什麼要虐待自己

那 我們今天就來寫代理模式Proxy

代理模式顧名思義就像有一個代理或是經紀人一樣來幫忙處理本務以外的事,想像今天你是主管,你有一堆文件需要簽,那麼當然不會是主管從各個不同部門拿這些文件過來簽,會有個秘書來幫您整理好這些文件,你只需要簽這些文件即可,這樣就是一種代理模式。
以實際網頁例子來說,假設今天要load一個圖出來,可以這麼寫:

var $img = (function () {
	var $img = $('<img>').appendTo('body');
	return {
		setSrc: function (src) {
			$img.attr('src', src);
		}
	}
})();
$img.setSrc('https://upload.cc/i1/2018/10/18/uCewa6.png');

如果網路很慢或是圖檔很大,在圖片被載好之前頁面會空白一片,因此我們可能需要從本地段先預載一個圖檔來提示使用者圖片正在載入中,所以可以這麼寫:

var $imgNode = (function() {
	var $imgNode = $('<img>').appendTo('body');
	var img = new Image;
	img.onload = function() {
		$imgNode.attr('src', this.src);
	};
	return {
		setSrc: function(src) {
			var loadingPage = 'loading.jpg';
			$imgNode.attr('src', loadingPage);
			img.src = src;
		}
	}
})();
$imgNode.setSrc('https://upload.cc/i1/2018/10/18/uCewa6.png');

在這裡我們的物件承擔了多項職責,我們的$imgNode除了下載圖片之外,還要處理預載圖片,這樣違反了單一職責原則,就可能或許幾年之後網路夠快不需要預載圖片的時候就必須改動$imgNode了。原則上我們盡量讓$imgNode只做載入圖片單一行為就好,然後再利用代理模式,作一個預載圖片的代理功能:

//保持單一功能
var $imgNode = (function() {
	var $imgNode = $('<img>').appendTo('body');
	return {
		setSrc: function(src) {
			$imgNode.attr('src', src);
		}
	}
})();

//預載代理
var proxyImage = (function() {
	var img = new Image;
	img.onload = function() {
		$imgNode.setSrc(this.src);
	};
	return {
		setSrc: function(src) {
			var loadingPage = 'loading.jpg';
			$imgNode.setSrc(loadingPage);
			img.src = src;
		}
	}
})();
proxyImage.setSrc('https://upload.cc/i1/2018/10/18/uCewa6.png');

以上就是一種代理模式寫法,另外再舉一個代理模式常用的狀況:利用代理模式合併HTTP請求。
我們要求每個checkbox勾選時都必須與server端同步資訊,所以可以這麼做:

(function() {
	for (let i = 1; i < 10; i++) {
		$('<input>').attr('type', 'checkbox').attr('id', i).appendTo('body').click(onClick);
	}

	function onClick(e) {
		if (this.checked === true) {
			syncWithServer(this.id);
		}
	}
})();

var syncWithServer = function(id) {
	console.log('假裝往server送訊息,id:' + id);
};

當每次勾選時都會往後端送訊息,因此我大量的勾選多個就會往後端送多少次,這種頻繁的網路請求容易造成系統消耗大量資源。所以,我們可以加入代理來蒐集一小段時間的網路請求,再一次性的發送給server:

var proxySync = (function() {
	var cache = []; //存放需要同步的ID;
	var timer;
	return function(id) {
		cache.push(id);
		if (timer) {
			return
		}
		timer = setTimeout(function() {
			syncWithServer(cache.join(','));
			clearTimeout(timer);
			timer = null;
			cache.length = 0;
		}, 2000);
	}
})();

做好之後只需要將此proxySync綁定勾選事件就好

(function() {
	for (let i = 1; i < 10; i++) {
		$('<input>').attr('type', 'checkbox').attr('id', i).appendTo('body').click(onClick);
	}

	function onClick(e) {
		if (this.checked === true) {
			proxySync(this.id);
		}
	}
})();

var syncWithServer = function(id) {
	console.log('假裝往server送訊息,id:' + id);
};

使用上就會降低HTTP Request的數量啦!

好的,以上就是代理模式啦,代理模式很常被使用到,很有用,但書上最後也表示:不必一開始就先猜測是否要使用代理模式,可以等有需要了再來編寫代理喔。


上一篇
JS Design Pattern Day02-策略模式 Strategy
下一篇
JS Design Pattern Day04-迭代器模式 Iterator
系列文
JS Design Pattern 30

尚未有邦友留言

立即登入留言