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和场景分析

更多的例子见请到smartjs的github上查看

 

 

 posted on 2014-06-22 15:14  Roy Zhang  阅读(1187)  评论(0编辑  收藏  举报