Dojo1.6新特性:Dojo Object Stores

來源:互聯網
上載者:User

本文翻譯自: Dojo Object
Stores

原作者: Kris Zyp

翻譯: Siqi

 

Dojo 1.6推出了一套新的名為Dojo Object Store的data store API。 這套基於HTML5 IndexedDB object
store API

的新store API旨在大大簡化Dojo store的互動和構建。

 

這套新的API遵循HTTP/REST命名規範,並與dojox.storage
providers

(local storage, cookie storage, 和 WebSQL
storage適用)以及其他所有符合這些開放標準的庫相容。

 

以下是這套新store API的幾條核心理念:

  • 使用者介面與資料分離

    – 這長久以來都是我們data API的設計目標。
    這些API協助我們將使用者介面與資料分離,從而使得我們可以對widgets或者data providers進行獨立的改進。

  • 簡單至上


    你可以簡單地建立一個帶有query()和get()方法的對象執行個體,這些方法的傳回值為objects,這個對象執行個體便是一個可用的store。當你想要添加別的功能時,例如建立新的對象,你可以添加一個add()方法,同樣的,你可以為更新對象功能引入一個put()方法。

  • 簡單JavaScript對象

    – 這套新的object store
    API使用簡單JavaScript對象而不是不透明項(opaque
    items)。在通過get()方法返回一個對象或是query()返回一個對象數組時,你可以使用for-in迴圈來訪問這些對象中的屬性。儲存對象只需要將一個簡單對象傳給put()方法就可以實現。

  • 基於Promise


    同步方法與非同步方法呼叫的介面是基本相同的,唯一的區別是同步方法直接傳回值而非同步方法呼叫返回promise。任何方法都可以選擇同步模式還是非同步模式(返回promise)。由於不再需要回呼函數,極大簡化了與已知的同步store的互動。同時非同步模式帶來的困擾被從介面上分離了出來,大大簡化了API。

  • 功能清晰


    不需要額外的方法來判斷一個store的功能。如果你想知道是否可以向一個store添加新的對象,只需要檢查它是否有add()方法;如果你想知道該store是否是可查詢的,只需要檢查它是否有query()方法。如果你想要建立一個唯讀store,只需要實現一些讀取函數(get,query,getIdentity)。

  • 功能層次化


    層次化的功能使得可以你可以從一個簡單、輕量級的store開始,逐步添加你需要的功能。Dojo核心庫配備了一個緩衝封裝器(caching
    wrapper)(dojo/store/Cache)來提高效能,以及一個資料變化通知封裝器(dojo/store/Observable)。這些store層次化的模組都是可選的並且可以將他們添加到任意store上。這使得我們可以將我們的核心store——dojo/store/Memory和dojo/store/JsonRest保持簡單、輕量,並讓使用者可以簡單地建立新store。

Dojo Object Store
API是一套介於不同的資料提供者和資料消費者之間的介面。使用者可以使用這套介面實現任意store,而Dojo核心庫本身配置了兩個常用的核心store——dojo/store/Memory和dojo/store/JsonRest。

 

簡單的: dojo/store/Memory

這是一個非常簡單的常駐記憶體(in-memory)store。它對於快速建立一個store是非常有用的,
特別是對於較小的資料集。只要簡單地提供一個數組作為資料來源,便可以建立出一個Memory
store,之後你便可以開始對該store進行查詢和互動。(更多使用細節請參見Memory object store
documentation

 

Memory store是一個同步模式的store,也就是說它直接傳回值,這令它使用起來非常簡單。例如:通過id來獲得一個對象:

 

var product = productStore.get("slinky");

 

需要再次強調的是,這個新的object store返回的是簡單的對象,所以我們可以很容易的擷取其中的屬性:

 

var name = product.name;

 

使用簡單對象也使得更新store非常簡單:

 

product.name = "New name";<br />productStore.put(product);

 

改進過的查詢功能是Dojo object
stores的新功能之一。查詢通過使用query()方法來實現,而返回的結果集提供一系列方便的迭代方法(interative
methods)——與dojo.query非常相似——同步模式和非同步模式的sotre都提供此功能。因此我們可以使用forEach,map,或是filter方法來操作結果集。Memory
Store支援多種形式的查詢。首先,我們可以通過索引值匹配(name-value
matches)來進行查詢(和Dojo.data中的ItemFileReadStore一樣)。以下我們根據category進行查詢:

 

store.query({category:"shoe"}).forEach(function(shoe){<br />// 每次匹配成功時被調用<br />});
 

 

索引值匹配提供了一種簡單的查詢機制,但是有時需要更複雜的查詢。Memory
store也接受函數來進行過濾,因此允許任意複雜查詢。例如,查詢所有價格低於10的產品:

 

store.query(function(product){<br />return product.price < 10;<br />}).forEach(function(shoe){<br />// 每次匹配成功時被調用<br />});

 

 

我們也可以通過函數名來引用函數,其本質是引用store中同名的方法。

 

store.lessThanTen = function(product){<br />return product.price < 10;<br />});<br />store.query("lessThanTen").forEach(function(shoe){<br />// 每次匹配成功時被調用<br />});

 

JSON 和REST: dojo/store/JsonRest

JsonRest
假定有一套伺服器端的API存在,且該套API旨在與store進行互動。它實現了一個健壯的、符合標準的HTTP/REST用戶端介面。dojo/store/JsonRest遵循REST高擴充性的原則,非常適合大資料集。JsonRest是一個非同步模式的store,其所有非同步方法呼叫返回promise(有一個列外:getIdentity方法永遠是同步的)。

 

Json Rest object
store與HTTP相容伺服器互動的方式與dojox.data.JsonRestStore十分相似。然而,JsonRest在store
API重構的過程中已經得到了極大的簡化。簡單地提供一個連結到伺服器的URL便可以建立出一個JsonRest store(更多使用細節請參見JsonRest object store
documentation

):

 

store = new dojo.store.JsonRest({target:"/Data/"});

store的方法十分直觀,與HTTP方法相對應。store.get(“some-id”)會發送一個GET請求到/Data/some-id並返回一個promise/Deferred作為結果。例如:

 

store.get("some-id").then(function(someObject){<br />// 使用someObject<br />});

 

store.remove(id)則會對應地發送一個DELETE請求。add(object)和put(object)也會同樣觸發相應的請求。如果傳給put(object)(或add(object))的object帶有identity屬性,則將會發送一個PUT請求。如果object不含有id或是第二個參數(options)包含一個值為true的incremental屬性,則將會發送一個POST請求。

 

如果options.overwrite為true的話,該請求會包含一個If-Match: *

header,若options.overwrite為false或是使用add(object)的話,則會包含一個If-None-Match:
*

header。這樣的伺服器之間的通訊一般在建立或是更改對象時發生。

 

同步與非同步標準化

 

如果你在寫一個同步非同步皆有的store的話,我們推薦使用dojo.when()。由於then()方法僅當store方法是非同步時才有效,因此這種情況下它並不值得完全依賴,我們可以使用dojo.when(),任何返回的值都將被恰當的處理。

 

dojo.when(store.get(id), function(object){<br />// 該函數將在get()方法完成時被調用,不論返回一個promise還是<br />// 直接返回一個值<br />});

 

dojo.when()方法可以被應用到所有store方法上。

 

用戶端資料緩衝: dojo/store/Cache

除了核心store的實現,Dojo還配備了兩個store封裝器(wrappers)。第一個是dojo/store/Cache。這個封裝器需要與兩個store一起使用:一個caching
store和一個master store。一個典型的Cache封裝器使用情境是將JsonRest作為master store, 將Memory
store作為用戶端的caching store。這使得你可以利用JsonRest store來與伺服器進行通訊,使用Memory
store來進行緩衝來避免不必要的HTTP請求。下面有一個例子來說明我們如何將它搭建起來:

 

memoryStore = new dojo.store.Memory({});<br />restStore = new dojo.store.JsonRest({target:"/Data/"});<br />store = new dojo.store.Cache(restStore, memoryStore);

 

現在我們可以使用我們整合了的store來執行一個查詢。下面我們將查詢所有的objects(我們可以省略查詢條件來查詢所對象):

 

var results = store.query();

 

這將使得返回結果被緩衝在memory store中。之後我們可以通過get()方法來擷取一個object而不需要額外發送一個HTTP請求:

 

object = store.get("some-id");

 

通過put(),add()和remove()方法對資料進行的改變都將反應到被緩衝的資料中。查詢通常要求細粒度的應用程式來控制哪些資料需要被緩衝,哪些不需要。因此,Cache
store不會嘗試自動查詢快取。但是,如果你選擇使用緩衝進行查詢的話,也沒有問題。可以簡單地查詢caching
store,也就是我們例子中的memoryStore:

 

memoryStore.query({category:"shoe"}).forEach(…);

監控資料變化: dojo/store/Observable

Dojo還配備了一個store封裝器來增加對資料變化通知的支援。Dojo object store API和遺留的Dojo Data
API的通知機制十分不同。舊的API存在一個問題,通知是store層面的,因此要決定一個事件如何真正地影響一個渲染好的資料集是不可能的。

 

Dojo object
store通過將通知事件的監控綁定到查詢的結果集上而不是store解決了這個問題。通過dojo/store/Observable模組,你可以封裝一個store,而封裝後的store得到的查詢結果集都是“可監控的(observable)”。也就是說,query()方法返回的對象/數組/promise都有一個可以被用來監視結果集變化的observe()方法。參見Observable store wrapper
documentation for the exact signature of the observe() method and
callback

。 

 

Observable
模組使得渲染一個結果集並即時根據底層資料的變化對介面進行更新變得非常容易。讓我們來看一個例子。我們將根據儲存的對象建立一個無序列表(<ul>)。首先,建立列表,然後我們將根據資料的變化做出反饋:

 

// 首先向我們的store添加監控功能<br />store = dojo.store.Observable(store);<br />var listNode = dojo.byId("list");<br />var itemNodes = [];<br />// 現在我們查詢資料<br />var shoes = store.query({category:"shoe"});<br />// 然後渲染返回的資料<br />shoes.forEach(function(shoe){<br />// 渲染每一個節點<br /> insertRow(shoe, itemNodes.length);<br />});<br />// 現在我們監控結果集的變化<br />shoes.observe(function(object, removedFrom, insertedInto){<br />if(removedFrom > -1){ // 刪除了的資料<br /> dojo.destroy(itemNodes[removedFrom]);<br /> itemNodes.splice(removedFrom, 1);<br />}<br />if(insertedInto > -1){ // 新資料或是更新了的資料<br /> insertRow(object, insertedInto);<br />}<br />});<br />function insertRow(product, index){<br />return itemNodes.splice(index, 0, dojo.create("li",<br />{innerHTML: product.name + ": " + product.price}, listNode));<br />}<br />

 

通過搭建起一個可以刪除行和添加行的監控函數,我們基本上可以應對任何資料變化,包括添加、刪除和更新。Observable模組甚至監控索引的更新,這使得如果結果集的排序順尋發生變化了的話,更新的對象也可以被正確地移動到一個新索引指向的地方。同時請注意,在本例中,通過監聽shoes結果集,我們只會獲得合格結果集中的相關更新。如果一個對象被更新、刪除或是添加,並且它的category屬性不是"shoe”,則沒有通知時間會被發送給相應的監聽器上。如果一個對象本來不是
“shoe”,之後被更新為一個"shoe”,這將觸發一個向結果集添加資料的通知。如果一個對象本來是"shoe”在更新之後不再是”shoe”,這將觸發一個從資料集中刪除資料的通知。

 

Observable模組還會向store添加一個notify()方法。這對於Comet-driven的即時應用程式是非常有用的,因為它們會非同步地從伺服器接受更新並將其告知store(和所有store結果集上的監聽器)。更多Dojo
1.6中Comet 和即時應用程式的相關細節請參見Dojo
Socket

 

與現存的Widget和Store協同工作

大多數Dijit widgets仍然基於遺留的Dojo Data API。但是,dojo配置了一個適配器(adapter)讓使用者可以在基於Dojo
Data的widget上使用新的object store。dojo/data/ObjectStore

模組作為一個是配置器接受一個object
store並返回一個data store。Dojo還配置了一個可以讓使用object store的widgets相容遺留的data store的適配器。dojo/store/DataStore

模組接受一個data store並返回一個object store。

 

層級結構

object store API定義了一個用來實現層級結構的方法——getChildren(object, options)。getChildren
一般被一個父object調用,並返回其子項目集。getChildren的實現一般根據應用程式的需求來定製,但是也有很多常用的實現方式:

  • 包含一個名為“children”
    的子項目數組

    – 通過這種方法,每一個對象在一個數組中定義它的子項目,因此特意地保留了子項目的順序。這種方法很適合較小的資料集。

  • 包含一個父元素的引用

     – 通過這種方法,每一個對象定義其父元素,通過查詢一個給定id的父元素下的所有對象便可以獲得其所有的子項目。這種方法比較適合可能需要入分頁或是排序等額外處理的大資料集

與其他Store相容

因為store API是一個常用的模式,所以很多庫的介面可以很容易的與store API相容。dojox.storage providers
的介面和store API就很類似,除了put()寫法有一點細微區別。可以很容易的將該方法進行轉換:

 

var storage = dojo.delegate(dojox.storage);<br />var storage.put = function(object, options){<br />var deferred = dojo.Deferred();<br /> dojox.storage.put(options.id || object.id, object, function(status){<br />if(status == dojox.storage.FAILED){<br /> deferred.reject(status);<br />}else if(status == dojox.storage.SUCCESS){<br /> deferred.resolve(status);<br />}<br />});<br />return deferred;<br />};

 

或者我們可以將Jens Arps StorageJS
library

進行轉換,其原本使用set()方法而不是put()方法:

 

var store = dojo.delegate(storage);<br />var store.put = function(object, options){<br />return storage.set(options.id || object.id, object);<br />};

 

StorageJS API還有一個allKeys()方法可以被轉換成query()方法。

Object Stores

為了吸取dojo.data的精華並符合HTML5 IndexedDB標準,同時簡化使用並使功能層次化,新的Dojo object
store構架被進行了徹底的重構。令人振奮的是現在我們終於可以使用這一新的手段來搭建我們的應用程式。同時我們很期待Dojo社區對於該設計的寶貴意見。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.