async-throttle-cache
Version:
Throttle or debounce asynchronous functions and return cached result for each function calls. It can be used for rate limit.
116 lines (114 loc) • 3.43 kB
JavaScript
var returnSelf = function returnSelf(result) {
return Promise.resolve(result);
};
function asyncThrottleCache(fn, wait, _temp) {
if (wait === void 0) {
wait = 0;
}
var _ref = _temp === void 0 ? {} : _temp,
_ref$key = _ref.key,
key = _ref$key === void 0 ? function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return JSON.stringify(args);
} : _ref$key,
_ref$serialize = _ref.serialize,
serialize = _ref$serialize === void 0 ? returnSelf : _ref$serialize,
_ref$deserialize = _ref.deserialize,
deserialize = _ref$deserialize === void 0 ? returnSelf : _ref$deserialize,
_ref$debounce = _ref.debounce,
debounce = _ref$debounce === void 0 ? undefined : _ref$debounce;
var cache = {};
var debounceLeading = debounce == null ? void 0 : debounce.leading;
return function () {
var _this = this;
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
// eslint-disable-line func-names
var cacheKey = key.apply(void 0, args);
var cached = cache[cacheKey];
var onFinish = function onFinish(index, err, result) {
var cachedF = cache[cacheKey];
if ((cachedF == null ? void 0 : cachedF.i) === index) {
cachedF.f = true;
if (err) {
cachedF.e = err;
cachedF.j.map(function (f) {
return f(err);
});
} else {
serialize(result).then(function (r) {
cachedF.r = r;
cachedF.s.map(function (f, i) {
return deserialize(r).then(f, cachedF.j[i]);
});
}, onFinish);
}
if (!cachedF.t || debounce && !debounceLeading) {
delete cache[cacheKey];
}
}
return result;
};
var exec = function exec() {
var cachedE = cache[cacheKey];
var i = cachedE.i = Date.now();
cachedE.f = false;
return fn.apply(_this, args).then(function (result) {
return onFinish(i, undefined, result);
}, function (err) {
onFinish(i, err);
return Promise.reject(err);
});
};
var timeout = function timeout() {
return setTimeout(function () {
var cachedT = cache[cacheKey];
if (cachedT) {
if (debounce && cachedT.s.length) {
exec();
} else if (cachedT.f) {
delete cache[cacheKey];
} else {
cachedT.t = 0;
}
}
}, wait);
};
var padding = function padding() {
return new Promise(function (resolve, reject) {
var cachedP = cache[cacheKey];
cachedP.s.push(resolve);
cachedP.j.push(reject);
});
};
if (cached) {
if (debounce) {
clearTimeout(cached.t);
cached.t = timeout();
} else {
var e = cached.e,
r = cached.r,
f = cached.f;
if (e !== undefined) {
return Promise.reject(e);
}
if (f) {
return deserialize(r);
}
}
return padding();
}
cache[cacheKey] = {
s: [],
// resolve callbacks
j: [],
// reject callbacks
t: timeout()
};
return !debounce || debounceLeading ? exec() : padding();
};
}
export default asyncThrottleCache;