关注分离是良好编程的基础。保持展示与数据的分离是关键。受到HTML5存储API的启发,Dojo对象存储架构为数据交互建立了统一的接口。
为什么要使用Dojo对象存储?
关注分离是有组织,可管理程序的基础,在web应用中分离点主要是指数据与用户接口(在MVC架构中用户接口通常是指试图和控制器)。受到HTML5存储API的启发,Dojo对象存储架构为数据交互建立了统一的接口。这些API是为促进松耦合的开发为存在的,可以让挂件和用户接口从多种源以一致的的方式与数据交互。
Dojo对象存储允许你开发和使用良好封装的组件很容易的连接多种数据源。Dojo对象存储是一个API,有很多叫做store的实现方式。存储包含一个简单的内存存储,JSON/REST存储,以及dojo.data存储和存储包裹器,它们提供一些额外的功能。
开始
最简单的存储就是dojo/store/Memory。我们可以提供一个对象数组给构造函数,然后就可以与之交互。一旦store被创建,我们可以使用query方法来查询。一种简单的方式就是提供一个对象的键值对来标识匹配对象必需的值。query方法一直返回一个对象或一个带有forEach方法的数组(像是map和filter):
1 require(["dojo/store/Memory"], function(Memory) { 2 var employees = [ 3 {name: "Jim", department: "accouting"}, 4 {name:"Bill", department:"engineering"}, 5 {name:"Mike", department:"sales"}, 6 {name:"John", department:"sales"} 7 ]; 8 9 var employeeStore = new Memory({data: employees, idProperty: "name"}); 10 employeeStore.query({department: "sales"}).forEach(function(employee) { 11 // this is called for each employee in the sales department 12 alert(employee.name); 13 }); 14 }
这样就可以弹出销售部门每个员工的名字了。
我们可以继续在这个store中创建新对象,删除对象:
1 // add a new employee 2 employeeStore.add({name: "George", department: "accounting"}); 3 4 // remove Bill 5 employeeStore.remove("Bill");
我们可以检索和更新数据。store中的对象作为JavaScript原生对象而存在,所以我们可以直接访问和修改对象的属性(当你变更属性时,确保你调用了put来保存更改):
1 // retrieve object with the name "Jim" 2 var jim = employeeStore.get("Jim"); 3 // show the department property 4 console.log("Jim's department is " jim.department); 5 // interate through all the properties of jim: 6 for(var i in jim) { 7 console.log(i, "=", jim[i]); 8 } 9 // update this department 10 jim.department = "engineering"; 11 // and store the change 12 employeeStore.put(jim);
再回到查询,我们可以为查询添加额外的参数。这些额外的参数可以限制查询返回的数量,排序对象,作为query方法的第二个参数使用。第二个参数可以是一个带有start与count属性的对象来限制查询返回的数量。使用限制数据集合对于较大的数据量的情况比较危险,此时应当使用带有分页功能的组件(如grid),将根据需要请求数据。第二个参数也可以带有sort参数,用于指定查询中的排序字段和排序方向:
1 employeeStore.query({department: "sales"}, { 2 // the results should the sorted by department 3 sort: [{attribute: "deparment", descending: false}], 4 // starting at on offset of 0 5 start: 0, 6 // with a limit of 10 objects 7 count: 10 8 }).map(function(employee) { 9 // return just the name, mapping to an array of names 10 return employee.name; 11 }).forEach(function(employeeName) { 12 console.log(employeeName); 13 });
Memory存储是一个同步的存储,意味着在执行每个动作后直接返回结果(get返回对象)。
dojo/store/JsonRest
另一个高可用的store是JsonRest存储,带有多种与服务器的交互动作,使用基于JSON的HTTP/REST标准。store的方法直接对应HTTP协议的GET,PUT,POST和DELETE方法。关于服务器端的详细信息参见JsonRest文档。
这里有一个异步存储的例子。一个异步存储返的方法返回一个承诺(promises)。我们可以promise返回的回调来使用promise。
1 require(["dojo/store/JsonRest"], function(JsonRest) { 2 employeeStore = new JsonRest({target: "/Employee/"}); 3 employeeStore.get("Bill").then(function(bill) { 4 // called once Bill was retrieved 5 }); 6 });
我们也可以使用Deferred.when()来处理,这些方法有可能是同步的或异步的,为了统一的行为而不去管具体实现。
这些例子展示了如何与store交互。我们限制可以开始构建与store交互的挂件与组件,具体的方式依赖于实现细节。我们也可以将我们的store与现有的组件关联起来。
例如,StoreSeries适配器可以允许我们将一个store作为图标的数据源。很多组件都可以使用store,只要你提供在store应有的查询即可:
1 // Note that while the Default plot2d module is not used explicity, it needs to 2 // be loaded to be able to create a Chart when no other plot is specified. 3 require([ 4 "dojox/charting/Chart", 5 "dojox/charting/StoreSeries", 6 /*, other deps, */ 7 "dojox/charting/plot2d/Default" 8 ], function(Chart, StoreSeries /*, other deps */) { 9 /* create stockStore here... */ 10 new Chart("lines"). 11 /* any other config of chart */ 12 // now use a data series from my store 13 addSeries("Price", new StoreSeries(stockStore, {query: {sector: "technology"}}, "price")).render(); 14 });
另一个Dojo存储的重要概念是通过store的包裹器来增加功能。Dojo带有一些增加功能的store包裹器,包括缓存包裹器,当数据改变时触发事件的观察包裹器。
本地存储
Dojo1.10在dojox中添加了本地存储dojo/store,支持IndexedDB和WebSQL。
dstore:dojo/store的未来
新的dstore是dojo/store的继承者,在Dojo1.8以后可用,还是Dojo2的计划API。如果你刚刚接触Dojo,建议你看看dstore。
总结
Dojo的对象存储是在1.6版本中添加的功能,它是一个有用的工具集,可以帮助我们实现数据与用户接口的关注分离。它提供了简答的API,帮助方便的自定义存储。更多信息请参见参考指南与下面的文章。
附加资源