數據服務的管理器;首先看下具體的代碼html
//數據服務 dataServices = st.factory({ name: "dataServices", proto: { //經過操做方法;type:操做類型; op:操做參數 operate: function(type, op) {…………}, //查詢方法;op:操做參數 search: function(op) {…………}, //更新方法;op:操做參數 update: function(op) {……} }, base: { //查詢接口 search: function(op) {}, //更新接口 update: function(op) {}, //通用初始化參數接口 initOptions : function(op){} } })
使用factory建立,加入了三個方法operate,search,update。使用的時候,直接經過這三個方法來操做具體註冊的數據服務(在op中設定dsType)。git
同時base定義了三個數據服務的三個基類接口,search,update,initOptions;github
op:既設置的參數(options,在smartjs中統一作op的簡寫),只有六個固定參數。其餘都是都是由具體的數據服務定義;api
op = { //數據服務類型 dsType : str, //過濾參數 param :obj, //過濾器 fitler : fn | obj //更新的數據 data :obj, //成功之後執行的方法 success : success, //失敗之後執行的方法 error : error };
其中,param與filter能夠根據不一樣的數據服務類型來區別使用,好比只是客戶端的能夠使用filter,服務端的能夠使用params;promise
注意:雖然op中有了success,error,但添加dataService的時候,儘可能使用promise的處理。緩存
經過dataServices的add(factory內置)的方法來註冊數據服務;實現了search和update兩個接口。另一個initOptions是須要對op初始化的是重寫異步
首先註冊一個模擬後臺異步數據服務 - server;只接受params來過濾數據:測試
var dataServices = st.dataServices, dataManager = st.dataManager, _db = [], _cache = []; //將params解析成過濾方法 function buildFilterByParams(params) { if (params) { return function(item) { var check = true; $.each(params, function(name, value) { if (item[name] !== value) { check = false; return check; } }) return check; } } } //取對象數據,測試使用array只取第一條 function getData(data) { return $.isArray(data) ? data[0] : data; } function buildFitler(filter) { if (filter && typeof filter === 'object') { return buildFilterByParams(filter); } return filter; } //模擬服務端異步返回數據,只接受params dataServices.add("server", { search: function(op) { //模擬異步查詢 setTimeout(function() { var result, filter = op.filter; result = filter ? _db.filter(filter) : _db; op.success && op.success(result); }, 100); }, update: function(op) { //模擬異步更新 setTimeout(function() { var filter = op.filter, data = getData(op.data); if (filter) { //測試使用,只更新第一條匹配數據 $.each(_db, function(i, item) { if (filter(item)) { _db[i] = data; return false; } }) } else { _db = op.data || []; } op.success && op.success(op.data); }, 100); }, initOptions: function(op) { //初始化設置參數將params編譯成filter過濾方法 op.filter = buildFilterByParams(op.params); } });
而後在註冊一個模擬客戶端取數據的緩存服務服務 - cache,使用filter進行過濾。ui
//模擬客戶端本地存儲 dataServices.add("cache", { search: function(op) { var result, filter = op.filter; result = filter ? _cache.filter(filter) : _cache; op.success && op.success(result); }, update: function(op) { var filter = op.filter, data = getData(op.data); if (filter) { //測試使用,只更新第一條匹配數據 $.each(_cache, function(i, item) { if (filter(item)) { _cache[i] = data; return false; } }) } else { _cache = op.data || []; } op.success && op.success(op.data); }, initOptions: function(op) { //生成fitler,當filter爲obj類型時,編譯成fn op.filter = buildFitler(op.filter); } });
看一下server的測試用例,直接使用dataServices對象進行操做,使用dsType來設置具體的數據類型;this
describe('dataServices Test', function() { it("update", function(endTest) { //更新server的數據 dataServices.update({ dsType: 'server', data: [{ name: 'user1', age: 20 }, { name: 'user2', age: 30 }], success: function(result) { expect(_db.length).toBe(2); endTest(); } }); }) it("search", function(endTest) { //從新server的數據 dataServices.search({ dsType: 'server', params: { name: 'user1' }, success: function(result) { expect(result.length).toBe(1); expect(result[0].age).toBe(20); endTest() } }); }) });
數據管理器,一樣使用factory構建,可是選用的類型爲'class',需動態初始化;擴展建立dm的方法-ceate和生成filter的方法-buildFilter;
另外在基類中,klassInit,get,set,onHandler,addHandler,fireHandler爲實現方法;其餘的都是接口,須要根據具體的數據管理進行實現;
//數據管理器 dataManager = st.factory({ name: "dataManager", type: "class", proto: { //建立dm方法 create: function(type, op) {}, //生成fitler方法 buildFilter: function(filter,conf) {} }, base: { klassInit: function(op) {}, //dm初始化方法 init: function(op) {}, //獲取數據 get: function(conf) {}, //設置數據 set: function(conf) {}, //註冊方法到事件委託,handler委託名稱:get,set,trigger onHandler: function(handler, fnName, fn, priority, mode) {}, //添加事件委託 addHandler: function() {}, //執行事件委託 fireHandler: function(name, args) {}, //dm內置查詢 innerSearch: function(op) {}, //dm內置更新 innerUpdate: function(op) {}, //檢查數據是否爲空 checkEmpty: function(data, conf) {}, //驗證方法 validate: function() {}, //清空方法 clear: function() {}, //初始化數據服務配置方法 setDataSerive : function(config){} } });
添加一個簡單的table類型的數據管理,(注只作測試演示,與真正的datamanger-table不是同一個)
//添加一個簡單的table類型的數據管理 dataManager.add("Table", { init: function() { this._data = []; }, //dm內置查詢 innerSearch: function(conf) { var filter = conf ? buildFitler(conf.filter) : null; return filter ? this._data.filter(filter) : this._data; }, //dm內置更新 innerUpdate: function(conf) { var isUpdate, _data = this._data, data = conf.data, updateData, filter; conf && (filter = buildFitler(conf.filter)); if (filter) { updateData = getData(data); //篩選數據 _data.forEach(function(item, i) { if (filter(item)) { _data[i] = updateData; isUpdate = true; return false; } }) isUpdate || _data.push(updateData); } else { this._data = data || []; } return data; }, //判斷數據是否爲空 checkEmpty: function(data, conf) { return data === undefined || data.length === 0; }, //清空數據 clear: function() { this._data = []; } });
在來看一下怎麼使用這個dm,下面列子中使用了內置的查詢和更新;
//建立一個tabel的manager var dm1 = dataManager.create("Table"); it("update", function() { dm1.innerUpdate({ data: [{ name: 'user1', age: 10 }] }); expect(dm1._data.length).toBe(1); expect(dm1._data[0].name).toBe('user1'); }) it("search", function() { var result = dm1.innerSearch(); expect(result.length).toBe(1); expect(result[0].name).toBe('user1'); }) it("update by filter", function() { //找不到匹配的數據,則插入新數據 dm1.innerUpdate({ data: { name: 'user3', age: 10 }, //方法過濾器 filter: function(user) { return user.name == 'user3'; } }); expect(dm1._data.length).toBe(2); expect(dm1._data[1].name).toBe('user3'); //更新數據 dm1.innerUpdate({ data: { name: 'user3', age: 40 }, //方法過濾器 filter: function(user) { return user.name == 'user3'; } }); expect(dm1._data.length).toBe(2); expect(dm1._data[1].age).toBe(40); }) it("search by filter", function() { var result = dm1.innerSearch({ //方法過濾器 filter: function(user) { return user.name == 'user3'; } }); expect(result.length).toBe(1); expect(result[0].age).toBe(40); }) it("search by params", function() { var result = dm1.innerSearch({ //參數過濾器 filter: { name: 'user3' } }); expect(result.length).toBe(1); expect(result[0].age).toBe(40); })
在結合dataService來看個查詢的例子,在這裏使用get操做,而不是innerSearch;get和set這兩個動做都會進入數據管理流程,策略纔會生效。而innerSearch和innerUpdate則是隻查詢dm內部。
在這個例子中,get動做會首先在dm內部查詢,找不到數據,在會進入ds查詢,而後將ds查詢的數據同步到dm中。(詳細的流程見dataManager介紹)
it("get from ds and update", function(endTest) { dm1.clear(); //首先會在dm內部查詢,找不到數據而後在到server上查詢 dm1.get({ //設置數據服務爲server dataServices: { dsType: 'server' }, success: function(result) { expect(result).toBeDefined(); expect(result[0].name).toBe('user1'); expect(dm1._data[0].name).toBe('user1'); endTest(); } }) }) it("get from ds and no update", function(endTest) { dm1.clear(); dm1.get({ //設置查詢不更新 update: false, dataServices: { dsType: 'server' }, success: function(result) { expect(dm1._data.length).toBe(0); endTest(); } }) })
在看一個set的例子:
it("set to ds", function(endTest) { //更新到ds dm1.set({ data: [{ name: "userUpdate" }], dataServices: { dsType: 'server' }, success: function(result) { expect(_db.length).toBe(1); expect(_db[0].name).toBe('userUpdate'); endTest(); } }) }) it("set to ds by params", function(endTest) { //根據條件更新到ds,條件同時在dm和ds中生效 dm1.set({ data: [{ name: "userUpdate" }], params: { id: 1 }, dataServices: { dsType: 'server' }, success: function(result) { expect(_db.length).toBe(2); expect(_db[0].name).toBe('userUpdate'); endTest(); } }) })
下篇詳細介紹策略參數的api和場景分析