batchloader
Version:
BatchLoader is a utility for data fetching layer to reduce requests via batching written in TypeScript. Inspired by Facebook's DataLoader
127 lines • 5.12 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var cacheloader_1 = require("./cacheloader");
var mappedbatchloader_1 = require("./mappedbatchloader");
var sleep = function (ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
};
var BatchLoader = (function () {
function BatchLoader(batchFn, keyToUniqueId, batchDelay, batchSize) {
if (batchDelay === void 0) { batchDelay = 0; }
if (batchSize === void 0) { batchSize = Number.MAX_SAFE_INTEGER; }
this.batchFn = batchFn;
this.keyToUniqueId = keyToUniqueId;
this.batchDelay = batchDelay;
this.batchSize = batchSize;
this.queuedKeys = [];
this.batchPromise = null;
}
BatchLoader.prototype.load = function (key) {
var queuedKeys = this.queuedKeys;
var index = queuedKeys.length;
queuedKeys.push(key);
return this.triggerBatch().then(function (values) { return values[index]; });
};
BatchLoader.prototype.loadMany = function (keys) {
if (keys.length) {
var queuedKeys = this.queuedKeys;
var index_1 = queuedKeys.length;
queuedKeys.push.apply(queuedKeys, keys);
var length_1 = keys.length;
return this.triggerBatch().then(function (values) {
return values.slice(index_1, index_1 + length_1);
});
}
return Promise.resolve([]);
};
BatchLoader.prototype.mapLoader = function (mapFn) {
return new mappedbatchloader_1.MappedBatchLoader(this, mapFn);
};
BatchLoader.prototype.cacheLoader = function (cache) {
return new cacheloader_1.CacheLoader(this, cache);
};
BatchLoader.prototype.triggerBatch = function () {
var _this = this;
return (this.batchPromise ||
(this.batchPromise = new Promise(function (resolve, reject) {
setTimeout(function () {
_this.batchPromise = null;
_this.runBatchNow().then(resolve, reject);
}, _this.batchDelay);
})));
};
BatchLoader.prototype.runBatchNow = function () {
var _a = this, queuedKeys = _a.queuedKeys, keyToUniqueId = _a.keyToUniqueId;
this.queuedKeys = [];
if (keyToUniqueId) {
var idMap = {};
var indexToId_1 = [];
var idToNewIndex_1 = {};
var newIndex = 0;
var uniqueKeys = [];
var len = queuedKeys.length;
for (var i = 0; i < len; i += 1) {
var key = queuedKeys[i];
var id = keyToUniqueId(key);
indexToId_1[i] = id;
if (idMap[id] !== true) {
idMap[id] = true;
idToNewIndex_1[id] = newIndex;
newIndex += 1;
uniqueKeys.push(key);
}
}
return this.maybeBatchInChunks(uniqueKeys).then(function (values) {
return queuedKeys.map(function (_key, i) { return values[idToNewIndex_1[indexToId_1[i]]]; });
});
}
return this.maybeBatchInChunks(queuedKeys);
};
BatchLoader.prototype.maybeBatchInChunks = function (keys) {
if (keys.length <= this.batchSize) {
return Promise.resolve(this.batchFn(keys));
}
return this.batchInChunks(keys);
};
BatchLoader.prototype.batchInChunks = function (keys) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, batchSize, batchDelay, promises, kLen, i, results, rLen, values, i;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = this, batchSize = _a.batchSize, batchDelay = _a.batchDelay;
promises = [];
kLen = keys.length;
i = 0;
_b.label = 1;
case 1:
if (!(i < kLen)) return [3, 4];
promises.push(this.batchFn(keys.slice(i, i + batchSize)));
if (!batchDelay) return [3, 3];
return [4, sleep(batchDelay)];
case 2:
_b.sent();
_b.label = 3;
case 3:
i += batchSize;
return [3, 1];
case 4: return [4, Promise.all(promises)];
case 5:
results = _b.sent();
rLen = results.length;
values = [];
for (i = 0; i < rLen; i += 1) {
values = values.concat(results[i]);
}
return [2, values];
}
});
});
};
return BatchLoader;
}());
exports.BatchLoader = BatchLoader;
//# sourceMappingURL=batchloader.js.map