RubyLouvre/anu

View on GitHub
packages/render/miniapp/apiForH5/storage.js

Summary

Maintainability
B
4 hrs
Test Coverage
const ERROR_MESSAGE = '不支持 localStorage !';
import { handleSuccess, handleFail } from '../utils';

function isSupportStorage() {
    if (!window.localStorage) {
        // eslint-disable-next-line no-console
        console.log(ERROR_MESSAGE);
        return false;
    }
    return true;
}

/**
 * 将数据储存在浏览器中指定的 key 中,会覆盖掉原来该 key 对应的内容
 * @method setStorage
 * @param  {String}   key  缓存中指定的 key
 * @param  {Object/String}   data 需要存储的内容
 */
function setStorage({
    key,
    data,
    success = () => {},
    fail = () => {},
    complete = () => {}
} = {}) {
    return new Promise((resolve, reject) => {
        if (!isSupportStorage()) {
            handleFail({ errMsg: ERROR_MESSAGE }, fail, complete, reject);
        } else {
            localStorage.setItem(key, JSON.stringify(data));
            handleSuccess({ key, data }, success, complete, resolve);
        }
    });
}

/**
 * setStorage 的同步版本
 * @method setStorageSync
 * @param  {String}   key  缓存中指定的 key
 * @param  {Object/String}   data 需要存储的内容
 */
function setStorageSync(key, data) {
    if (!isSupportStorage()) {
        return;
    }
    localStorage.setItem(key, JSON.stringify(data));
}

/**
 * 获取缓存数据
 * @method getStorage
 * @param  {String}   key 缓存中指定的 key
 */
function getStorage({
    key,
    success = () => {},
    fail = () => {},
    complete = () => {}
} = {}) {
    return new Promise((resolve, reject) => {
        if (!isSupportStorage()) {
            handleFail({ errMsg: ERROR_MESSAGE }, fail, complete, reject);
        } else {
            handleSuccess(
                { data: JSON.parse(localStorage.getItem(key)) },
                success,
                complete,
                resolve
            );
        }
    });
}

/**
 * getStorage 的同步版本
 * @method getStorageSync
 * @param  {String}         key 缓存中指定的 key
 * @return {Object/String}  key 对应的数据
 */
function getStorageSync(key) {
    if (!isSupportStorage()) {
        return;
    }
    return JSON.parse(localStorage.getItem(key));
}

/**
 * 从缓存中移除指定 key
 * @method removeStorage
 * @param  {String}      key 缓存中指定的 key
 */
function removeStorage({
    key,
    success = () => {},
    fail = () => {},
    complete = () => {}
} = {}) {
    return new Promise((resolve, reject) => {
        if (!isSupportStorage()) {
            handleFail({ errMsg: ERROR_MESSAGE }, fail, complete, reject);
        } else {
            localStorage.removeItem(key);
            handleSuccess(null, success, complete, resolve);
        }
    });
}

/**
 * removeStorage 的同步版本
 * @method removeStorageSync
 * @param  {String}          key 缓存中指定的 key
 */
function removeStorageSync(key) {
    if (!isSupportStorage()) {
        return;
    }
    localStorage.removeItem(key);
}

/**
 * 清空缓存数据
 * @method clearStorage
 */
function clearStorage({
    success = () => {},
    fail = () => {},
    complete = () => {}
} = {}) {
    return new Promise((resolve, reject) => {
        if (!isSupportStorage()) {
            handleFail({ errMsg: ERROR_MESSAGE }, fail, complete, reject);
        } else {
            localStorage.clear();
            handleSuccess(null, success, complete, resolve);
        }
    });
}

/**
 * clearStorage 的同步版本
 * @method clearStorageSync
 */
function clearStorageSync() {
    if (!isSupportStorage()) {
        return;
    }
    localStorage.clear();
}

// 返回 10KB 大小的字符串
function get10KBStr() {
    let str = '0123456789';
    function add(s) {
        s += str;
        if (s.length === 10240) {
            str = s;
            return;
        }
        add(s);
    }
    add(str);
    return str;
}

let LIMIT_SIZE_CACHE = -1;
// 获取 localStorage 剩余容量 KB
function getStorageUnusedSize(cb) {
    if (LIMIT_SIZE_CACHE !== -1) {
        cb(LIMIT_SIZE_CACHE);
    } else {
        const _10KBStr = get10KBStr();
        let sum = _10KBStr;
        const id = setInterval(function() {
            sum += _10KBStr;
            try {
                localStorage.removeItem('test');
                localStorage.setItem('test', sum);
            } catch (e) {
                LIMIT_SIZE_CACHE = sum.length / 1024;
                cb(LIMIT_SIZE_CACHE);
                clearInterval(id);
            }
        }, 1);
    }
}
// 获取 localStorage 使用容量 KB
// 有个奇怪的问题,localStorage.setItem('length', 100)
// localStorage.valueOf() 或 Object.keys(localStorage) 里并没有 length
// 只能使用 localStorage.getItem('length')获取到
function getStorageUsedSize() {
    const values = Object.values(localStorage.valueOf());
    return values.reduce((size, value) => value.length, 0) / 1024;
}

/**
 * getStorageInfo 的同步版本
 * @method getStorageInfoSync
 * @param  {Boolean}          [needLimitSize=false] 是否需要 storage 限制的空间大小
 * @return {Object}                                 keys,currentSize,limitSize
 */
async function getStorageInfoSync(needLimitSize = false) {
    const result = await getStorageInfo({ needLimitSize });
    return result;
}

/**
 * 获取当前 storage 的相关信息
 * 由于 limitSize 采用的是不断向 storage 添加直至添满来得到的,耗费性能和时间(只在第一次,之后使用缓存值),所以需要的时候传入 needLimitSize 为 true
 * 第一次要等待 10多秒。。。
 * @method getStorageInfo
 * @param  {Boolean}       needLimitSize 是否需要 storage 限制的空间大小
 */
function getStorageInfo({
    needLimitSize = false,
    success = () => {},
    fail = () => {},
    complete = () => {}
} = {}) {
    return new Promise((resolve, reject) => {
        if (!isSupportStorage()) {
            handleFail({ errMsg: ERROR_MESSAGE }, fail, complete, reject);
            return;
        }
        const result = {
            keys: Object.keys(localStorage),
            currentSize: getStorageUsedSize()
        };
        if (needLimitSize) {
            getStorageUnusedSize(unUsedSize => {
                handleSuccess(
                    {
                        ...result,
                        limitSize: result.currentSize + unUsedSize
                    },
                    success,
                    complete,
                    resolve
                );
            });
        } else {
            handleSuccess(result, success, complete, resolve);
        }
    });
}

export default {
    setStorage,
    setStorageSync,
    getStorage,
    getStorageSync,
    removeStorage,
    removeStorageSync,
    clearStorage,
    clearStorageSync,
    getStorageInfo,
    getStorageInfoSync
};