choerodon-ui
Version:
An enterprise-class UI design language and React-based implementation
444 lines (373 loc) • 10.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"];
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
exports.refreshCacheOptions = refreshCacheOptions;
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _mobx = require("mobx");
var _configure = require("../configure");
var _Yallist = _interopRequireDefault(require("./Yallist"));
// 双向链表 -> 缓存更新性能优化
var MAX = Symbol('max'); // 最大值
var LENGTH = Symbol('length'); // 长度
var LENGTH_CALCULATOR = Symbol('lengthCalculator'); // 长度计算
var ALLOW_STALE = Symbol('allowStale'); // 允许过时
var MAX_AGE = Symbol('maxAge'); // 最大时效(缓存时长)
var DISPOSE = Symbol('dispose'); // 处置 处理
var NO_DISPOSE_ON_SET = Symbol('noDisposeOnSet'); // 不可处理
var LIST = Symbol('list'); // 列表
var CACHE = Symbol('cache'); // 缓存
var UPDATE_AGE_ON_GET = Symbol('updateAgeOnGet'); // 获取更新时效
var naiveLength = function naiveLength() {
return 1;
};
/**
* 是否过时
* @param self
* @param hit
*/
function isStale(self, hit) {
if (!hit || !hit.maxAge && !self[MAX_AGE]) return false;
var diff = Date.now() - hit.now;
return hit.maxAge ? diff > hit.maxAge : self[MAX_AGE] && diff > self[MAX_AGE];
}
/**
* 删除
* @param self
* @param node
*/
function _del(self, node) {
if (node) {
var hit = node.value;
if (self[DISPOSE]) self[DISPOSE](hit.key, hit.value);
self[LENGTH] -= hit.length;
self[CACHE]["delete"](hit.key);
self[LIST].removeNode(node);
}
}
/**
* 获取
* @param self
* @param key
* @param doUse
*/
function _get(self, key, doUse) {
var node = self[CACHE].get(key);
if (node) {
var hit = node.value;
if (isStale(self, hit)) {
_del(self, node);
if (!self[ALLOW_STALE]) return undefined;
} else if (doUse) {
if (self[UPDATE_AGE_ON_GET]) node.value.now = Date.now();
self[LIST].unshiftNode(node);
}
return hit.value;
}
}
/**
* 修整
* @param self
*/
function trim(self) {
if (self[LENGTH] > self[MAX]) {
for (var walker = self[LIST].tail; self[LENGTH] > self[MAX] && walker !== null;) {
// We know that we're about to delete this one, and also
// what the next least recently used key will be, so just
// go ahead and set it now.
var prev = walker.prev;
_del(self, walker);
walker = prev;
}
}
}
/**
* 遍历步骤
* @param self
* @param fn
* @param node
* @param thisp
*/
function forEachStep(self, fn, node, thisp) {
var hit = node.value;
if (isStale(self, hit)) {
_del(self, node);
if (!self[ALLOW_STALE]) hit = undefined;
}
if (hit) fn.call(thisp, hit.value, hit.key, self);
}
/**
* 构造 Entry 类
*/
var Entry = /*#__PURE__*/(0, _createClass2["default"])(function Entry(key, value, length, now) {
var maxAge = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
(0, _classCallCheck2["default"])(this, Entry);
this.key = key;
this.value = value;
this.length = length;
this.now = now;
this.maxAge = maxAge;
});
/**
* 导出 Cache 类
*/
var Cache = /*#__PURE__*/function () {
function Cache(options) {
(0, _classCallCheck2["default"])(this, Cache);
if (typeof options === 'number') options = {
max: options
};
if (!options) options = {};
if (options.max && (typeof options.max !== 'number' || options.max < 0)) throw new TypeError('max must be a non-negative number');
this[MAX] = options.max || 0;
var lc = options.length || naiveLength;
this[LENGTH_CALCULATOR] = typeof lc !== 'function' ? naiveLength : lc;
this[ALLOW_STALE] = options.stale || false;
if (options.maxAge && typeof options.maxAge !== 'number') throw new TypeError('maxAge must be a number');
this[MAX_AGE] = options.maxAge || 0;
this[DISPOSE] = options.dispose;
this[NO_DISPOSE_ON_SET] = options.noDisposeOnSet || false;
this[UPDATE_AGE_ON_GET] = options.updateAgeOnGet || false;
this.reset();
} // resize the cache when the max changes.
(0, _createClass2["default"])(Cache, [{
key: "max",
get: function get() {
return this[MAX];
},
set: function set(mL) {
if (typeof mL !== 'number' || mL < 0) throw new TypeError('max must be a non-negative number');
this[MAX] = mL || Infinity;
trim(this);
}
}, {
key: "allowStale",
get: function get() {
return this[ALLOW_STALE];
},
set: function set(allowStale) {
this[ALLOW_STALE] = !!allowStale;
}
}, {
key: "maxAge",
get: function get() {
return this[MAX_AGE];
} // resize the cache when the lengthCalculator changes.
,
set: function set(mA) {
if (typeof mA !== 'number') throw new TypeError('maxAge must be a non-negative number');
this[MAX_AGE] = mA;
trim(this);
}
}, {
key: "lengthCalculator",
get: function get() {
return this[LENGTH_CALCULATOR];
},
set: function set(lC) {
var _this = this;
if (typeof lC !== 'function') lC = naiveLength;
if (lC !== this[LENGTH_CALCULATOR]) {
this[LENGTH_CALCULATOR] = lC;
this[LENGTH] = 0;
this[LIST].forEach(function (hit) {
hit.length = _this[LENGTH_CALCULATOR](hit.value, hit.key);
_this[LENGTH] += hit.length;
});
}
trim(this);
}
}, {
key: "length",
get: function get() {
return this[LENGTH];
}
}, {
key: "itemCount",
get: function get() {
return this[LIST].length;
}
}, {
key: "rforEach",
value: function rforEach(fn, thisp) {
thisp = thisp || this;
for (var walker = this[LIST].tail; walker !== null;) {
var prev = walker.prev;
forEachStep(this, fn, walker, thisp);
walker = prev;
}
}
}, {
key: "forEach",
value: function forEach(fn, thisp) {
thisp = thisp || this;
for (var walker = this[LIST].head; walker !== null;) {
var next = walker.next;
forEachStep(this, fn, walker, thisp);
walker = next;
}
}
}, {
key: "keys",
value: function keys() {
return this[LIST].toArray().map(function (k) {
return k.key;
});
}
}, {
key: "values",
value: function values() {
return this[LIST].toArray().map(function (k) {
return k.value;
});
}
}, {
key: "reset",
value: function reset() {
var _this2 = this;
if (this[DISPOSE] && this[LIST] && this[LIST].length) {
this[LIST].forEach(function (hit) {
return _this2[DISPOSE](hit.key, hit.value);
});
}
this[CACHE] = new Map(); // hash of items by key
this[LIST] = new _Yallist["default"](); // list of items in order of use recency
this[LENGTH] = 0; // length of items in the list
}
}, {
key: "dump",
value: function dump() {
var _this3 = this;
return this[LIST].map(function (hit) {
return isStale(_this3, hit) ? false : {
k: hit.key,
v: hit.value,
e: hit.now + (hit.maxAge || 0)
};
}).toArray().filter(function (h) {
return h;
});
}
}, {
key: "dumpLru",
value: function dumpLru() {
return this[LIST];
}
}, {
key: "set",
value: function set(key, value, maxAge) {
maxAge = maxAge || this[MAX_AGE];
if (maxAge && typeof maxAge !== 'number') throw new TypeError('maxAge must be a number');
var now = maxAge ? Date.now() : 0;
var len = this[LENGTH_CALCULATOR](value, key);
if (this[CACHE].has(key)) {
if (len > this[MAX]) {
_del(this, this[CACHE].get(key));
return false;
}
var node = this[CACHE].get(key);
var item = node.value;
if (this[DISPOSE]) {
if (!this[NO_DISPOSE_ON_SET]) this[DISPOSE](key, item.value);
}
item.now = now;
item.maxAge = maxAge;
item.value = value;
this[LENGTH] += len - item.length;
item.length = len;
this.get(key);
trim(this);
return true;
}
var hit = new Entry(key, value, len, now, maxAge);
if (hit.length > this[MAX]) {
if (this[DISPOSE]) this[DISPOSE](key, value);
return false;
}
this[LENGTH] += hit.length;
this[LIST].unshift(hit);
this[CACHE].set(key, this[LIST].head);
trim(this);
return true;
}
}, {
key: "has",
value: function has(key) {
if (!this[CACHE].has(key)) return false;
var hit = this[CACHE].get(key).value;
return !isStale(this, hit);
}
}, {
key: "get",
value: function get(key) {
return _get(this, key, true);
}
}, {
key: "peek",
value: function peek(key) {
return _get(this, key, false);
}
}, {
key: "pop",
value: function pop() {
var node = this[LIST].tail;
if (!node) return null;
_del(this, node);
return node.value;
}
}, {
key: "del",
value: function del(key) {
_del(this, this[CACHE].get(key));
}
}, {
key: "load",
value: function load(arr) {
this.reset();
var now = Date.now(); // A previous serialized cache has the most recent items first
for (var l = arr.length - 1; l >= 0; l--) {
var hit = arr[l];
var expiresAt = hit.e || 0;
if (expiresAt === 0) // the item was created without expiration in a non aged cache
this.set(hit.k, hit.v);else {
var maxAge = expiresAt - now; // dont add already expired items
if (maxAge > 0) {
this.set(hit.k, hit.v, maxAge);
}
}
}
}
}, {
key: "prune",
value: function prune() {
var _this4 = this;
this[CACHE].forEach(function (_value, key) {
return _get(_this4, key, false);
});
}
}]);
return Cache;
}();
exports["default"] = Cache;
function refreshCacheOptions(cache) {
return (0, _mobx.reaction)(function () {
return (0, _configure.getConfig)('lookupCache') || {};
}, function (lookupCache) {
if ('max' in lookupCache) {
cache.max = lookupCache.max;
}
if ('maxAge' in lookupCache) {
cache.maxAge = lookupCache.maxAge;
}
if ('stale' in lookupCache) {
cache.allowStale = lookupCache.stale;
}
if ('length' in lookupCache) {
cache.lengthCalculator = lookupCache.length;
}
});
}
//# sourceMappingURL=index.js.map