cache2
Version:
一个简单的 JavaScript 缓存管理,支持浏览器端和 node 端。
300 lines (292 loc) • 9.79 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var tslib = require('tslib');
var Emitter = require('emitter-pro');
var cache = {};
var MemoryStorage = (function () {
function MemoryStorage(scope) {
if (scope === void 0) { scope = 'default'; }
this.scope = scope;
if (!cache[this.scope]) {
cache[this.scope] = {};
}
this.data = cache[this.scope];
}
MemoryStorage.prototype.getItem = function (key) {
return key in this.data ? this.data[key] : null;
};
MemoryStorage.prototype.setItem = function (key, value) {
this.data[key] = value;
};
MemoryStorage.prototype.removeItem = function (key) {
delete this.data[key];
};
MemoryStorage.prototype.clear = function () {
cache[this.scope] = {};
this.data = cache[this.scope];
};
return MemoryStorage;
}());
function randomString() {
return Math.random().toString(16).substring(2, 8);
}
function isStorageSupported(storage) {
try {
var isSupport = typeof storage === 'object' &&
storage !== null &&
!!storage.setItem &&
!!storage.getItem &&
!!storage.removeItem;
if (isSupport) {
var key = randomString() + new Date().getTime();
var value = '1';
storage.setItem(key, value);
if (storage.getItem(key) !== value) {
return false;
}
storage.removeItem(key);
}
return isSupport;
}
catch (err) {
console.error("[cache2] ".concat(storage, " is not supported. The default memory cache will be used."));
return false;
}
}
function parse(value, reviver) {
try {
return JSON.parse(value, reviver);
}
catch (err) {
return value;
}
}
function stringify(value, replacer) {
return JSON.stringify(value, replacer);
}
var Storage = (function () {
function Storage(storage, options) {
if (options === void 0) { options = {}; }
var isSupported = storage ? isStorageSupported(storage) : false;
this.options = tslib.__assign({ needParsed: isSupported, prefix: '' }, options);
this.storage = isSupported ? storage : new MemoryStorage(this.options.memoryScope);
}
Storage.prototype.getKey = function (key) {
return this.options.prefix + key;
};
Storage.prototype.get = function (key) {
var value = this.storage.getItem(this.getKey(key));
return this.options.needParsed ? parse(value, this.options.reviver) : value;
};
Storage.prototype.set = function (key, value) {
this.storage.setItem(this.getKey(key), this.options.needParsed ? stringify(value, this.options.replacer) : value);
};
Storage.prototype.del = function (key) {
this.storage.removeItem(this.getKey(key));
};
Storage.prototype.clear = function () {
if (typeof this.storage.clear === 'function') {
this.storage.clear();
}
};
return Storage;
}());
var defaultPrefix = 'cache2_';
var defaultNamespace = 'default';
var Cache = (function (_super) {
tslib.__extends(Cache, _super);
function Cache(namespace, options) {
var _this = _super.call(this) || this;
var ns = defaultNamespace, opts;
if (typeof namespace === 'string') {
ns = namespace || defaultNamespace;
}
else if (typeof namespace === 'object') {
opts = namespace;
}
if (!opts && typeof options === 'object') {
opts = options;
}
_this.options = tslib.__assign({ max: -1, stdTTL: 0, maxStrategy: 'limited', checkperiod: 0, prefix: defaultPrefix }, opts);
_this.storage = new Storage(_this.options.storage, tslib.__assign({ memoryScope: ns }, _this.options));
_this.cacheKey = ns;
_this.startCheckperiod();
return _this;
}
Cache.prototype._check = function (key, data) {
var ret = true;
if (data.t !== 0 && data.t < Date.now()) {
ret = false;
this.del(key);
this.emit('expired', key, data.v);
}
return ret;
};
Cache.prototype._wrap = function (value, ttl) {
var now = Date.now();
var currentTtl = typeof ttl === 'number' ? ttl : this.options.stdTTL;
var livetime = currentTtl > 0 ? now + currentTtl : 0;
return {
v: value,
t: livetime,
n: now
};
};
Cache.prototype._isLimited = function (len) {
return this.options.max > -1 && len >= this.options.max;
};
Cache.prototype._getReplaceKey = function (keys, cacheValues) {
var retkey = keys[0];
keys.forEach(function (key) {
if (cacheValues[retkey].n > cacheValues[key].n) {
retkey = key;
}
});
return retkey;
};
Object.defineProperty(Cache.prototype, "cacheValues", {
get: function () {
return this.storage.get(this.cacheKey) || {};
},
enumerable: false,
configurable: true
});
Cache.prototype.setCacheValues = function (values) {
this.storage.set(this.cacheKey, values);
};
Cache.prototype._getData = function (key, cacheValues) {
var data = cacheValues[key];
if (data && this._check(key, data)) {
return data;
}
return;
};
Cache.prototype.get = function (key) {
var data = this._getData(key, this.cacheValues);
return data === null || data === void 0 ? void 0 : data.v;
};
Cache.prototype.mget = function (keys) {
var _this = this;
var ret = {};
if (!Array.isArray(keys)) {
return ret;
}
var cacheValues = this.cacheValues;
keys.forEach(function (key) {
var data = _this._getData(key, cacheValues);
if (data) {
ret[key] = data.v;
}
});
return ret;
};
Cache.prototype.getAll = function () {
var keys = Object.keys(this.cacheValues);
return this.mget(keys);
};
Cache.prototype.set = function (key, value, ttl) {
if (this.options.max === 0) {
return false;
}
var cacheValues = this.cacheValues;
var keys = Object.keys(cacheValues);
if (!cacheValues[key] && this._isLimited(keys.length)) {
var validKeys = this.keys();
if (this._isLimited(validKeys.length)) {
if (this.options.maxStrategy === 'replaced') {
var replaceKey = this._getReplaceKey(validKeys, cacheValues);
this.del(replaceKey);
}
else {
return false;
}
}
}
cacheValues[key] = this._wrap(value, ttl);
this.setCacheValues(cacheValues);
this.emit('set', key, cacheValues[key].v);
return true;
};
Cache.prototype.mset = function (keyValueSet) {
var _this = this;
var ret = true;
keyValueSet.forEach(function (item) {
var itemSetResult = _this.set(item.key, item.value, item.ttl);
if (ret && !itemSetResult) {
ret = false;
}
});
return ret;
};
Cache.prototype.del = function (key) {
var _this = this;
var cacheValues = this.cacheValues;
var count = 0;
var keys = Array.isArray(key) ? key : [key];
keys.forEach(function (key) {
if (cacheValues[key]) {
count++;
var oldData = cacheValues[key];
delete cacheValues[key];
_this.emit('del', key, oldData.v);
}
});
if (count > 0) {
this.setCacheValues(cacheValues);
}
return count;
};
Cache.prototype.clear = function () {
this.storage.del(this.cacheKey);
};
Cache.prototype.keys = function () {
var _this = this;
var cacheValues = this.cacheValues;
var keys = Object.keys(cacheValues);
return keys.filter(function (key) { return _this._check(key, cacheValues[key]); });
};
Cache.prototype.has = function (key) {
return !!this._getData(key, this.cacheValues);
};
Cache.prototype.take = function (key) {
var ret;
var data = this._getData(key, this.cacheValues);
if (data) {
ret = data.v;
this.del(key);
}
return ret;
};
Cache.prototype.ttl = function (key, ttl) {
var data = this._getData(key, this.cacheValues);
if (data) {
return this.set(key, data.v, ttl);
}
return false;
};
Cache.prototype.getTtl = function (key) {
var data = this._getData(key, this.cacheValues);
return data === null || data === void 0 ? void 0 : data.t;
};
Cache.prototype.getLastModified = function (key) {
var data = this._getData(key, this.cacheValues);
return data === null || data === void 0 ? void 0 : data.n;
};
Cache.prototype.startCheckperiod = function () {
var _this = this;
this.keys();
if (this.options.checkperiod > 0) {
clearTimeout(this._checkTimeout);
this._checkTimeout = setTimeout(function () {
_this.startCheckperiod();
}, this.options.checkperiod);
}
};
Cache.prototype.stopCheckperiod = function () {
clearTimeout(this._checkTimeout);
};
return Cache;
}(Emitter));
exports.Cache = Cache;
exports.Storage = Storage;
exports.default = Cache;