另一方面,由於 JavaScript 通常會和宿主環境(比如瀏覽器)緊密結合,因此缺乏功能強大而簡單易用的開發工具。在這樣的環境中,開發組件或架構成為一項具有挑戰的工作。
這次,我們將以一個簡易的 JavaScript 組件開發為契機,逐步展開組件的分析、設計、實現、構建和測試等任務,探討組件開發過程涉及的方方面面。這些探討將分 4 篇陸續張貼出來(連結將在張貼後更新):
- 分析和設計組件
- 編碼實現和演算法
- 用 Ant 構建組件
- 測試 JavaScript 組件
現在,假設我們要從頭開始設計並實現一個隊列管理組件,先讓我們來認識一下隊列:
Queue
圖片來自 Wikipedia.
隊列是一個“先進先出”(FIFO) 的資料結構,只能向它的尾巴追加項,項從頭部取出使用,這個規則將應用到我們所探討的組件中去。對於隊列,相信學過 C 或是資料結構課程的同學已有所瞭解,如果你已經把它還給了老師,請使用搜尋引擎簡單瞭解一下隊列的知識。
這個隊列管理組件具體要實現的功能是:它是個工作管理員,按高、中、低優先順序維護著三個任務隊列,客戶(使用者)可以在任何時候把想要執行的任務添加到某個隊列,可以指定任務啟動並執行上下文,並傳給它必要的資料。客戶也可以隨時運行這個隊列,隊列裡的任務按照指定的依賴關係以合理的方式依次運行。
為了不至於使組件過於簡單而缺乏實用性,我們特意給它添加了一些“糖”:分優先順序、傳入上下文和資料、處理依賴關係。如果把上面這段理解為需求的話,那麼首先,我們要從中提取出最重要的關鍵詞,它們直接決定了這個組件應該如何設計:
然後,我們從中提煉出涉及的對象:
- 工作管理員 (TaskManager): 從目前需求來看,它只需要一個執行個體。
- 隊列 (Queue): 每個優先順序對應一個隊列,由
TaskManager
管理這三個 Queue
執行個體。
- 任務 (Task): 描述添加的任務,放在相應優先順序的
Queue
裡面。
- 依賴 (Dependency): 描述單一的依賴,即
Task1
依賴 Task2
, 顯然某個 Task
可能具有多個依賴。
它的物件模型可以大概表示如下:
設計初期的對象圖
注意到 Dependency
實際上並沒有做什麼事,而 Queue
的兩個方法可以分別交給 TaskManager
& Task
來負責。一個方法到底由哪個對象負責,是很容易引起爭論的話題,不在我們的討論範圍內。這次,我們的重點是,採用 JavaScript 實現這個組件,結合 JavaScript 獨特的語言特性,我們設想實現上述四個對象:
TaskManager
直接通過對象 (Object) 實現。在 JavaScript 的世界,對象可以作為天然的靜態類來使用——你可以直接在“類” ClassObject
裡面定義屬性方法 property
,並以靜態類的方式來引用 CassObject.property
.
Queue
以數組 (Array) 的形式體現出來,Task
則是數組中存放的每一項。對 Queue
進行操作必然要在其 prototype 中定義一些執行個體方法,由於每個 Queue 執行個體都是原生的數組,為了減少對 Array.prototype
的侵入,我們可以考慮將這些方法定義到 Task.prototype
上——將職責轉移到任務上。
將三個 Queue
數組集結在一起,形成一個“大數組”以表示三個不同優先順序的隊列,這個大數組可以作為 TaskManager
的屬性。
- 任務的核心是一個 function, 本來可以直接用 function 來表示一個任務,但考慮到它具有自身獨特的屬性(優先順序、依賴等等),而且是最經常被操作的對象,以後可能還會進行擴充,所以我們決定單獨將其定義成對象。
- 依賴直接以數組的形式作為
Task
的一個屬性存在——Task
將依賴的其他多個 Task
標識符放在這個數組中,不再單獨定義這個對象。
分析下來,局勢逐漸明朗——我們需要將四個對象簡化成兩個:TaskManager
& Task
, 另外兩個對象用原生的數組來實現:
簡化後的物件模型
又注意到這裡多次以數組來實現,而編碼過程中必然涉及到數組的遍曆、尋找等操作,JavaScript 1.6 已經為我們實現了這些數組操作。為了充分利用數組內建的原生方法,又能在較老的瀏覽器中運行,我們使用了 Eric 的代碼。這樣,我們可以直接使用諸如 forEach
/indexOf
等方法,更關注組件的功能實現,而且在現代瀏覽器中獲得較好的效能。
~~~~~~~~~~~~~ 八卦分割線 ~~~~~~~~~~~~~
嗯,在嚴肅地分析了組件設計之後,就要踏上快樂的編碼實現之旅了。別急,TaskManager
似乎俗氣了一點:不足以表達具有優先順序、依賴管理的任務隊列,而且用它做命名空間有跟其他代碼衝突的可能性。好吧,這個組件就叫 Smart Queue
吧,響亮而又獨特.^^
分析設計好了,名字也有了,欲知具體實現過程,且聽下回分解。