用数据访问对象模式(DAO)封装本地存储

306 阅读3分钟
大部分网站会将一些数据存储在前端,用来实现页面间的传值,对于一些大型Web应用来说,其存储的数据可能会非常多,数据的管理会变得复杂,并且一个大型项目是由多位程序员共同开发的,这时就会遇到两个问题:
  • 如何确保自己存储在本地的数据不会覆盖掉其他人的?
  • 如何知道本地存储的数据是否成功?
  • 如何定期清除本地数据?
这时候就可以使用**数据访问对象模式**来解决。
数据访问对象模式(Data Access Object Pattern)即不直接通过数据对象,而是抽象成Dao层来做这个事情。
数据访问对象类的基本结构如下,我们给键值添加了一段前缀用来避免键值冲突,并且在值中加入数据过期时间戳以及分隔符,获取值的时候再进行判断是否过期,这样可以更灵活地管理存储数据的生命周期,这是很有必要的,它能方便日后对数据的管理(如定期清除数据)。这里还用到了回调的方式,方便获取数据访问过程的具体结果,并且返回操作的状态,以便知道本地存储的数据是否成功。
  /**
        * LocalStorage数据访问类
        * @param {string} prefix Key前缀
        * @param {string} timeSplit 时间戳与存储数据之间的分割符
        */
        var Myls = function (prefix, timeSplit) {
            this.prefix = prefix;
            this.timeSplit = timeSplit || '|-|';
        }
        // LocalStorage数据访问类原型方法
        Myls.prototype = {
            // 操作状态
            status: {
                SUCCESS: 0,     // 成功
                FAILURE: 1,     // 失败
                OVERFLOW: 2,    // 溢出
                TIMEOUT: 3      // 过期
            },
            // 本地存储对象
            storage: localStorage || window.localStorage,
            // 获取带前缀的真实键值
            getKey: function (key) {
                return this.prefix + key;
            },
            /**
             * 添加(修改)数据
             * @param key 数据字段标识
             * @param value 数据值
             * @param callback 回调函数
             * @param time 过期时间
             */
            set: function (key, value, callback, time) {
                // 默认为成功状态
                var status = this.status.SUCCESS,
                    key = this.getKey(key);
                try {
                    // 获取过期时间戳
                    time = new Date(time).getTime() || time.getTime();
                } catch (e) {
                    // 未设置过期时间时默认为一个月
                    time = new Date().getTime() + 1000 * 60 * 60 * 24 * 30;
                }
                try {
                    // 向本地存储中添加(修改)数据
                    this.storage.setItem(key, time + this.timeSplit + value);  //1602412148898|-|abc
                } catch (e) {
                    // 发生溢出
                    status = this.status.OVERFLOW;
                }
                // 执行回调并传入参数
                callback && callback.call(this, status, key, value);
            },
            /**
            * 获取数据
            * @param key 数据字段标识
            * @param callback 回调函数
            */
            get: function (key, callback) {
                var key = this.getKey(key),
                    status = this.status.SUCCESS,    // 获取数据状态
                    value = null;    // 获取数据值

                try {
                    // 从本地存储获取数据
                    value = this.storage.getItem(key);

                } catch (e) {
                    // 获取数据失败
                    status = this.status.FAILURE;
                    value = null;
                }

                // 如果成功获取数据
                if (status !== this.status.FAILURE) {
                    var index = value.indexOf(this.timeSplit),
                        timeSplitLen = this.timeSplit.length,
                        // 获取时间戳
                        time = value.slice(0, index);
                    // 判断数据是否未过期
                    if (new Date(1 * time).getTime() > new Date().getTime() || time == 0) {
                        // 获取数据值
                        value = value.slice(index + timeSplitLen);
                    } else {
                        // 数据已过期,删除数据
                        value = null;
                        status = this.status.TIMEOUT;
                        this.remove(key);
                    }
                }

                // 执行回调
                callback && callback.call(this, status, value);
                // 返回结果值
                return value;
            },
            /**
            * 删除数据
            * @param key 数据字段标识
            * @param callback 回调函数
            */
            remove: function (key, callback) {
                // 设置默认状态为失败
                var status = this.status.FAILURE,
                    key = this.getKey(key),
                    value = null;
                try {
                    // 获取数据值
                    value = this.storage.getItem(key);
                } catch (e) {
                    // 数据不存在,不采取操作
                }
                // 如果数据存在
                if (value) {
                    try {
                        // 删除数据
                        this.storage.removeItem(key);
                        status = this.status.SUCCESS;
                    } catch (e) {
                        // 数据删除失败,不采取操作
                    }
                }
                // 执行回调并传入参数,删除成功则传入被删除的数据值
                callback && callback.call(this, status, status > 0 ? null : value.slice(value.indexOf(this.timeSplit) + this.timeSplit.length));
            }
        }

测试

   var Myls = new Myls('LS_');
    // 添加/修改数据
    Myls.set('token', 'abc', function () { console.log(arguments); });
    // 获取数据
    var value = Myls.get('token', function (val) { console.log(arguments); });
    console.log(value);
    // 删除数据
    Myls.remove('token', function () { console.log(arguments); });