dataServices
数据服务的管理器;首先看下具体的代码
//数据服务
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)。
同时base定义了三个数据服务的三个基类接口,search,update,initOptions;
op:既设置的参数(options,在smartjs中统一做op的简写),只有六个固定参数。其他都是都是由具体的数据服务定义;
op = {
//数据服务类型
dsType : str,
//过滤参数
param :obj,
//过滤器
fitler : fn | obj
//更新的数据
data :obj,
//成功以后执行的方法
success : success,
//失败以后执行的方法
error : error
};
其中,param与filter可以根据不同的数据服务类型来区别使用,比如只是客户端的可以使用filter,服务端的可以使用params;
注意:虽然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进行过滤。
//模拟客户端本地存储
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来设置具体的数据类型;
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()
}
}); })
});
dataManager
数据管理器,同样使用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){}
}
});
添加datamanger示例
添加一个简单的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和场景分析