話說上期我們討論了隊列管理組件的設計,並且給它取了個響亮而獨特的名字:Smart Queue. 這次,我們要將之前的設計成果付諸實踐,用代碼來實現它。
首先,我們要考慮一下它的原始檔案佈局,也就是決定程式碼如何拆分到獨立的檔案中去。為什麼要這麼做呢?還記得上期結尾處我提到這個元件會使用「外部程式碼」嗎?為了區分程式碼的用途,決定將程式碼至少分成兩部分:外部程式碼檔案和Smart Queue 檔案。
區分用途只是其一,其二,分散到獨立文件有利於程式碼的維護。試想,以後的某一天你決定要在現有的佇列管理基本功能之上,加入一些新的擴充功能,或是把它包裝成某個實現特定任務的元件,而又希望保持現有功能(內部實作)和呼叫方式(對外介面)不變,那麼將新的程式碼寫到單獨的檔案是最好的選擇。
嗯,下期會重點談談文件佈局的話題,現在要開始切入正題了。第一步,當然是要為元件創建自己的命名空間,元件所有的程式碼都會限制在這個頂層命名空間內:
var SmartQueue = window.SmartQueue || {};
SmartQueue.version = '0.1';
初始化的時候,如果碰到命名空間衝突就把它拉過來用。通常這個衝突是由重複引用組件程式碼導致的,因此「拉過來用」會將物件以同樣的實作重寫一次;最壞的情況下,如果碰巧頁面上另一個物件也叫SmartQueue, 那不好意思了,我會覆蓋你的實作——如果沒有進一步的命名衝突,基本上兩個元件可以相安無事地運行。同時順便給它一個版本號碼。
接著,以三個優先權為SmartQueue 建立三個佇列:
var Q = SmartQueue.Queue = [[], [], []];
每個都是空數組,因為還沒有任務加進去嘛。又順便給它建個“快捷方式”,後面要訪問數組直接寫Q[n] 就可以啦。
接下來,我們的主角Task 隆重登場-怎麼new 一個Task, 定義在這裡:
裡面的具體細節就不說了,有必要的註釋,一般我們的程式碼也能做到自我描述,後面程式碼也是這樣。這裡告訴客戶(使用者):你想新建一個SmartQueue.Task 實例,就要至少傳一個參數給這個建構函式(後3 個都可以省略進行預設處理),否則拋出異常伺候。
但這還不夠,有時候,客戶希望從已有Task 克隆一個新實例,或從一個「殘廢體」(具有部分Task 屬性的物件)修復出「健康體」(真正的Task 物件實例),透過上面的構造方式就有點不爽了──客戶得這樣寫:
var task1 = new SmartQueue.Task(obj.fn, 1, '', obj.dependencies);
出處: Alipay UED
var T = SmartQueue.Task = function(fn, level, name, dependencies) {
if(typeof fn !== FUNCTION) {
throw new Error('Invalid argument type: fn.');
}
this.fn = fn;
this.level = _validateLevel(level) ? level : LEVEL_NORMAL;
// detect type of name
this.name = typeof name === STRING && name ? name : 't' + _id++;
// dependencies could be retrieved as an 'Object', so use instanceof instead.
this.dependencies = dependencies instanceof Array ? dependencies : [];
};